home *** CD-ROM | disk | FTP | other *** search
Wrap
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Board.c # Board.h # BoardP.h # DirMgr.c # DirMgr.h # Directory.c # Directory.h # FileSel.c # FileSel.h # FileSelP.h # Makefile.1 # MultiList.c # MultiList.h # MultiListP.h # Prop.lst # README # README.X11 # RegExp.c # RegExp.h # Rules # Sample.01 # Sample.02 # ScrList.c # ScrList.h # ScrListP.h # Smart-Go.def # Spec.io # advunix.c # advunix.h # build.c # comment.c # doit.c # edit.c # format # goserver.c # help.c # imakefile # mailgo # mailgo.6 # mgt.6 # mgt.c # mgt.h # parse.c # play.c # proto.h # shared.h # tree.c # wrapmgt.6 # wrapmgt.c # x11.4.c # xutil.c # xutil.h # This archive created: Wed Feb 24 16:59:47 1993 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'Board.c' then echo shar: "will not over-write existing file 'Board.c'" else cat << \SHAR_EOF > 'Board.c' /* Board.c * * Copyright (c) 1992 by Tim Casey and Chien-Min Wang. * All rights reserved. */ #include <stdio.h> #include <ctype.h> #include <assert.h> #include <X11/keysymdef.h> #include <X11/StringDefs.h> #include <X11/IntrinsicP.h> #include <X11/Xaw/FormP.h> #include <X11/Xaw/ViewportP.h> #include "Board.h" #include "BoardP.h" #define InitSize 504 /* = 21 * 24 */ #define MinWidth 150 #define HT_INC(w) (w->board.length / (w->board.boardsize + 2)) #define WD_INC(w) (w->board.length / (w->board.boardsize + 2)) #define HT_COORD_PIX(n, w) (w->board.htinc * (w->board.boardsize - (n)) + w->board.htinc / 2) #define WD_COORD_PIX(n, w) (w->board.wdinc * ((n) + 1) + w->board.wdinc / 2) #define DEG_X_ANGLE(d) (d * 64) #define GET_PIECE(w,i,j) ((w)->board.pieces[i][j].p) #define GET_MARK(w,i,j) ((w)->board.pieces[i][j].m) #define GET_LETTER(w,i,j) ((w)->board.pieces[i][j].l) extern XtAppContext app_context; int resized = 0; static void pseudo_realize(), redisplay(); static XtInitProc initialize(); static XtActionProc CallButtonUp(), CallButtonDown(), CallKeyDown(); static XtWidgetProc destroy(); static char translations[] = "<BtnUp>: button_up() \n\ <BtnDown>: button_down() \n\ <KeyDown>: key_down() \n\ "; static XtActionsRec actions[] = { /* {name, procedure}, */ {"button_up", (XtActionProc)CallButtonUp}, {"button_down", (XtActionProc)CallButtonDown}, {"key_down", (XtActionProc)CallKeyDown}, }; #define offset(field) XtOffset(BoardWidget, board.field) static XtResource resources[] = { {XtNboardSize, XtCBoardSize, XtRInt, sizeof(int), offset(boardsize), XtRString, "19"}, {XtNboardColor, XtCBoardColor, XtRPixel, sizeof(Pixel), offset(boardcolor), XtRString, "tan1"}, {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(foreground), XtRString, "black"}, {XtNboardFont, XtCBoardFont, XtRFontStruct, sizeof( XFontStruct * ), offset(font), XtRString, XtDefaultFont}, {XtNbuttonUp, XtCButtonUp, XtRCallback, sizeof( caddr_t ), offset(Bup), XtRPointer, NULL}, {XtNbuttonDown, XtCButtonDown, XtRCallback, sizeof( caddr_t ), offset(Bdown), XtRPointer, NULL}, {XtNkeyDown, XtCKeyDown, XtRCallback, sizeof( caddr_t ), offset(Kdown), XtRPointer, NULL}, }; #undef offset(field) void PutCStr(w, s, len, wd, ht, drawable) BoardWidget w; char *s; int len, wd, ht; { int x, y; int width, height; GC tmpGC, invGC; unsigned long GCMask; XGCValues GCValues; Display *theDisplay = XtDisplay(w); GCMask = GCFont | GCForeground | GCBackground; GCValues.background = w->board.foreground; GCValues.foreground = w->board.foreground; GCValues.font = w->board.font->fid; tmpGC = XtGetGC(w, GCMask, &GCValues); GCMask = GCForeground | GCBackground; GCValues.background = w->board.boardcolor; GCValues.foreground = w->board.boardcolor; invGC = XtGetGC(w, GCMask, &GCValues); width = XTextWidth( w->board.font, s, len); height = w->board.font->ascent + w->board.font->descent; x = wd - (width / 2); y = ht + (height / 2) - 2; if (x < 0) x = 0; if (x > w->core.width) x = w->core.width; if (y > w->core.height) y = w->core.height; XFillRectangle(theDisplay, drawable, invGC, x - 2, y - (height / 2) - 4, width + 4, height + 2); XDrawString(theDisplay, drawable, tmpGC, x, y, s, len); XtReleaseGC(w, tmpGC); } static void redisplay( w, evnt, regn) BoardWidget w; XEvent *evnt; Region regn; { #ifdef DEBUG fprintf(stderr, "redisplay called\n"); #endif XCopyArea(XtDisplay(w), w->board.board, w->core.window, w->board.gc, 0, 0, w->core.width, w->core.height, 0, 0); } static void resize( w ) BoardWidget w; { int i, j; BWPiece p; BWMark m; char l; #ifdef DEBUG fprintf(stderr, "resize called\n"); #endif if (resized == 0) { resized = 1; return; } if ( ! XtIsRealized( w ) ) return; destroy(w); pseudo_realize(w); XCopyArea( XtDisplay(w), w->board.backing, w->board.board, w->board.gc, 0, 0, w->core.width, w->core.height, 0, 0); for(i=0 ; i < w->board.boardsize ; i++ ) { for(j=0 ; j < w->board.boardsize ; j++) { p = GET_PIECE (w, i, j); m = GET_MARK (w, i, j); l = GET_LETTER(w, i, j); BWPutPiece (w, i, j, p); BWSetMark (w, i, j, m); BWSetLetter(w, i, j, l); } } } void reconfig(bw, fw, vw) BoardWidget bw; FormWidget fw; ViewportWidget vw; { int diff, diff1, diff2; FormConstraints form; diff1 = bw->core.width - bw->core.height; diff2 = MinWidth - fw->core.width; diff = (diff1 > diff2) ? diff1 : diff2; diff += (bw->core.width - diff) % 21; if (diff == 0) { resize(bw); return; } form = (FormConstraints) bw->core.constraints; form->form.virtual_width = bw->core.width - diff; XtResizeWidget(bw, bw->core.width - diff, bw->core.height, bw->core.border_width); form = (FormConstraints) fw->core.constraints; form->form.virtual_width = fw->core.width + diff; XtMoveWidget(fw, fw->core.x - diff, fw->core.y); XtResizeWidget(fw, fw->core.width + diff, fw->core.height, fw->core.border_width); form = (FormConstraints) vw->core.constraints; form->form.virtual_width = vw->core.width + diff; XtMoveWidget(vw, vw->core.x - diff, vw->core.y); XtResizeWidget(vw, vw->core.width + diff, vw->core.height, vw->core.border_width); } static Boolean setVals( cur, req, new ) BoardWidget cur, req, new; { return( False ); } /* Need a fake realize, so I can use it to re-do the board pixmaps, * for resizing. */ static XtRealizeProc realize(w, mask, attr) BoardWidget w; Mask *mask; XSetWindowAttributes *attr; { #ifdef DEBUG fprintf(stderr, "realize called\n"); #endif XtCreateWindow(w, InputOutput, (Visual *) CopyFromParent, *mask, attr); /* I hope, from some x docs. */ pseudo_realize(w); return 0; } static int pts[21][2] = { {0, 1}, {0, 1}, /* 1 */ {0, 1}, {0, 1}, {0, 1}, {0, 1}, /* 5 */ {0, 1}, {0, 1}, {0, 1}, {2, 4}, /* 9 */ {0, 1}, {3, 4}, /* 11 */ {0, 1}, {3, 3}, /* 13 */ {0, 1}, {0, 1}, /* 15 */ {0, 1}, {0, 1}, /* 17 */ {0, 1}, {3, 6}, /* 19 */ {0, 1}, }; static void SetUpStarPts(w) BoardWidget w; { int brdsz = w->board.boardsize; int st, inc; int i, j; Dimension x, y; Display *theDpy = XtDisplay(w);; st = pts[brdsz][0]; inc = pts[brdsz][1]; for(i=st ; i < brdsz ; i += inc ) { for(j=st ; j < brdsz ; j += inc ) { x = WD_COORD_PIX(i, w); y = HT_COORD_PIX(j, w); XFillRectangle(theDpy, w->board.backing, w->board.gc, x - 2, y - 2, 5, 5); } } } /* * This is called on resize as well as "realize". * I should create the GCs in "realize" */ static void pseudo_realize(w) BoardWidget w; { Dimension wd, ht, stonewd, stoneht, st, end; unsigned long GCMask; XGCValues GCVals; GC invGC; Display *theDisplay; Window boardWindow; int i; char label[3]; #ifdef DEBUG fprintf(stderr, "pseudo_realize called\n"); #endif /* DEBUG */ boardWindow = w->core.window; theDisplay = XtDisplay(w); w->board.length = (w->core.width <= w->core.height) ? w->core.width : w->core.height; wd = w->core.width; ht = w->core.height; stoneht = w->board.htinc = HT_INC(w); stonewd = w->board.wdinc = WD_INC(w); /* * Pixmap hell */ w->board.backing = XCreatePixmap(theDisplay, boardWindow, wd, ht, w->core.depth); w->board.board = XCreatePixmap(theDisplay, boardWindow, wd, ht, w->core.depth); w->board.white = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); w->board.black = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); w->board.dame = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); w->board.bterr = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); w->board.wterr = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); w->board.last = XCreatePixmap(theDisplay, boardWindow, stonewd, stoneht, w->core.depth); GCMask = GCForeground | GCBackground; GCVals.foreground = w->board.foreground; GCVals.background = w->core.background_pixel; w->board.gc = XCreateGC( theDisplay, w->board.board, GCMask, &GCVals ); GCVals.background = w->board.boardcolor; GCVals.foreground = w->board.boardcolor; invGC = XCreateGC( theDisplay, w->board.board, GCMask, &GCVals ); XFillRectangle( theDisplay, w->board.backing, invGC, 0, 0, wd, ht ); XFillRectangle( theDisplay, w->board.board, invGC, 0, 0, wd, ht ); XFillRectangle( theDisplay, w->board.black, invGC, 0, 0, stonewd, stoneht ); XFillRectangle( theDisplay, w->board.white, invGC, 0, 0, stonewd, stoneht ); XFillRectangle( theDisplay, w->board.dame, invGC, 0, 0, stonewd, stoneht ); XFillRectangle( theDisplay, w->board.bterr, invGC, 0, 0, stonewd, stoneht ); XFillRectangle( theDisplay, w->board.wterr, invGC, 0, 0, stonewd, stoneht ); st = WD_COORD_PIX(0, w); end = WD_COORD_PIX(w->board.boardsize - 1, w); for(i=0 ; i < w->board.boardsize ; i++ ) { int pos; sprintf(label,"%2d", i+1); pos = HT_COORD_PIX(i, w); XDrawLine(theDisplay, w->board.backing, w->board.gc, st, pos, end, pos); PutCStr(w, label, 2, st - stonewd, pos, w->board.backing); PutCStr(w, label, 2, end + stonewd, pos, w->board.backing); } st = HT_COORD_PIX(0, w); end = HT_COORD_PIX(w->board.boardsize - 1, w); for(i=0 ; i < w->board.boardsize ; i++ ) { int pos; label[0] = INDEX_TO_CHAR(i); pos = WD_COORD_PIX(i, w); XDrawLine(theDisplay, w->board.backing, w->board.gc, pos, st, pos, end); PutCStr(w, label, 1, pos, st + stoneht, w->board.backing); PutCStr(w, label, 1, pos, end - stoneht, w->board.backing); } SetUpStarPts( w ); /* * the piece pixmaps */ XFillArc(theDisplay, w->board.black, w->board.gc, 0, 0, w->board.wdinc-1, w->board.htinc-1, 0, DEG_X_ANGLE(360)); XDrawArc(theDisplay, w->board.black, w->board.gc, 0, 0, w->board.wdinc-1, w->board.htinc-1, 0, DEG_X_ANGLE(360)); XSetForeground(theDisplay, invGC, w->core.background_pixel); XSetBackground(theDisplay, invGC, w->board.boardcolor); XFillArc(theDisplay, w->board.white, invGC, 0, 0, w->board.wdinc-1, w->board.htinc-1, 0, DEG_X_ANGLE(360)); XSetForeground(theDisplay, invGC, w->board.foreground); XDrawArc(theDisplay, w->board.white, invGC, 0, 0, w->board.wdinc-1, w->board.htinc-1, 0, DEG_X_ANGLE(360)); /* * Territory */ XFillRectangle(theDisplay, w->board.bterr, w->board.gc, stonewd/4, stoneht/4, stonewd/2, stoneht/2); XSetForeground(theDisplay, invGC, w->core.background_pixel); XSetBackground(theDisplay, invGC, w->board.boardcolor); XFillRectangle(theDisplay, w->board.wterr, invGC, stonewd/4, stoneht/4, stonewd/2, stoneht/2); XSetForeground(theDisplay, invGC, w->board.foreground); XDrawRectangle(theDisplay, w->board.wterr, invGC, stonewd/4, stoneht/4, stonewd/2, stoneht/2); /* * dame */ XDrawRectangle(theDisplay, w->board.dame, w->board.gc, stonewd/4, stoneht/4, stonewd/2, stoneht/2); XDrawLine(theDisplay, w->board.dame, w->board.gc, stonewd/4, stoneht/4, 3 * stonewd/4, 3 * stoneht/4); XDrawLine(theDisplay, w->board.dame, w->board.gc, stonewd/4, 3 * stoneht/4, 3 * stonewd/4, stoneht/4); XFreeGC( theDisplay, invGC ); } static XtWidgetProc destroy(w) BoardWidget w; { Display *theDisplay = XtDisplay(w); if ( ! XtIsRealized( w ) ) return 0; /* * Pixmap hell */ XFreePixmap(theDisplay, w->board.board); XFreePixmap(theDisplay, w->board.backing); XFreePixmap(theDisplay, w->board.white); XFreePixmap(theDisplay, w->board.black); XFreePixmap(theDisplay, w->board.dame); XFreePixmap(theDisplay, w->board.bterr); XFreePixmap(theDisplay, w->board.wterr); XFreePixmap(theDisplay, w->board.last); XFreeGC( theDisplay, w->board.gc ); return 0; } static XtActionProc CallButtonUp( w, evnt, str, n ) BoardWidget w; XButtonEvent *evnt; /* we know it to be a union */ String *str; Cardinal *n; { evnt->x = (evnt->x - w->board.wdinc) / w->board.wdinc; if (evnt->x >= w->board.boardsize) evnt->x = evnt->y = -1; evnt->y = w->board.boardsize - (evnt->y / w->board.htinc); if (evnt->y >= w->board.boardsize) evnt->x = evnt->y = -1; XtCallCallbacks( w, XtNbuttonUp, evnt); return 0; } static XtActionProc CallButtonDown( w, evnt, str, n ) BoardWidget w; XButtonEvent *evnt; /* we know it to be a union */ String *str; Cardinal *n; { evnt->x = (evnt->x - w->board.wdinc) / w->board.wdinc; if (evnt->x >= w->board.boardsize) evnt->x = evnt->y = -1; evnt->y = w->board.boardsize - (evnt->y / w->board.htinc); if (evnt->y >= w->board.boardsize) evnt->x = evnt->y = -1; XtCallCallbacks( w, XtNbuttonDown, evnt); return 0; } static XtActionProc CallKeyDown( w, evnt, str, n ) BoardWidget w; XButtonEvent *evnt; /* we know it to be a union */ String *str; Cardinal *n; { XtCallCallbacks( w, XtNkeyDown, evnt ); return 0; } static XtActionProc CallResize( w, evnt, str, n ) BoardWidget w; XButtonEvent *evnt; /* we know it to be a union */ String *str; Cardinal *n; { XtCallCallbacks( w, XtNresize, evnt); return 0; } static void ClassInitialize(); BoardClassRec boardClassRec = { { (WidgetClass) &widgetClassRec, (String) "Board", (Cardinal) sizeof(BoardRec), (XtProc) ClassInitialize, /* called only once */ (XtWidgetClassProc) NULL, /* class part init */ (Boolean) False, (XtInitProc) initialize, (XtArgsProc) NULL, (XtRealizeProc) realize, (XtActionList) actions, (Cardinal) XtNumber(actions), (XtResourceList) resources, (Cardinal) XtNumber( resources ), (XrmClass) NULLQUARK, (Boolean) False, (Boolean) True, /* Compress exposure */ (Boolean) False, (Boolean) True, /* Visible interest */ (XtWidgetProc) destroy, (XtWidgetProc) resize, (XtWidgetProc) redisplay, (XtSetValuesFunc) setVals, (XtArgsFunc) NULL, /* set vals hook */ (XtAlmostProc) XtInheritSetValuesAlmost, (XtArgsProc) NULL, (XtAcceptFocusProc) NULL, (XtVersionType) XtVersion, NULL, (String) NULL, (XtGeometryHandler) XtInheritQueryGeometry, (XtStringProc) XtInheritDisplayAccelerator, (caddr_t) NULL }, { NULL, NULL, } }; WidgetClass boardWidgetClass = (WidgetClass)&boardClassRec; static XtInitProc initialize( req, new ) BoardWidget req, new; { if (req->core.height <= 0) new->core.height = InitSize; if (req->core.width <= 0) new->core.width = InitSize; new->board.curhx = -1; /* flag for highlight */ XtAugmentTranslations((Widget) new, boardClassRec.board_class.translations); /* * Need to put in something to protect the color of the board. * If tan1 was not allocated, then the background needs to be white. */ return 0; } static void ClassInitialize() { boardClassRec.board_class.translations = XtParseTranslationTable( translations ); } static void BWUpdatePos(w, i, j) BoardWidget w; int i, j; { Dimension x, y; #ifdef DEBUG fprintf(stderr, "UpdatePos called %d %d\n", i, j); #endif x = WD_COORD_PIX(i, w) - w->board.wdinc / 2; y = HT_COORD_PIX(j, w) - w->board.htinc / 2; XCopyArea( XtDisplay( w ), w->board.board, w->core.window, w->board.gc, x, y, w->board.wdinc, w->board.htinc, x, y ); } void BWUpdateBoard( w ) BoardWidget w; { #ifdef DEBUG fprintf(stderr, "UpdateBoard called\n"); #endif XCopyArea( XtDisplay( w ), w->board.board, w->core.window, w->board.gc, 0, 0, w->core.width, w->core.height, 0, 0 ); } void BWClearBoard( w ) BoardWidget w; { long GCMask; XGCValues GCVals; GC tmpgc; #ifdef DEBUG fprintf(stderr, "ClearBoard called\n"); #endif GCMask = GCForeground | GCBackground; GCVals.foreground = w->core.background_pixel; GCVals.background = w->board.foreground; tmpgc = XtGetGC( w, GCMask, &GCVals ); /* * XCopyArea backing --> board */ BWUpdateBoard( w ); w->board.curhx = -1; XtReleaseGC( w, tmpgc ); } void BWReset(w) BoardWidget w; { int i, j; #ifdef DEBUG fprintf(stderr, "Reset called\n"); #endif XCopyArea( XtDisplay(w), w->board.backing, w->board.board, w->board.gc, 0, 0, w->core.width, w->core.height, 0, 0); BWUpdateBoard(w); w->board.curhx = -1; for(i=0 ; i < w->board.boardsize ; i++) { for(j=0 ; j < w->board.boardsize ; j++) { w->board.pieces[i][j].p = Empty; w->board.pieces[i][j].m = NoMark; w->board.pieces[i][j].l = '\0'; } } } void BWUnhighlight(w) BoardWidget w; { int x, y; #ifdef DEBUG fprintf(stderr, "Unhighlight called\n"); #endif if (w->board.curhx == -1) return; x = WD_COORD_PIX(w->board.curhx, w) - w->board.wdinc / 2; y = HT_COORD_PIX(w->board.curhy, w) - w->board.htinc / 2; XCopyArea(XtDisplay(w), w->board.last, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); BWUpdatePos(w, w->board.curhx, w->board.curhy); w->board.curhx = -1; } void BWHighlightPiece(w, i, j) BoardWidget w; int i, j; { Dimension x, y; #ifdef DEBUG fprintf(stderr, "HighlightPiece called %d %d\n", i, j); #endif BWUnhighlight(w); x = WD_COORD_PIX(i, w) - w->board.wdinc / 2; y = HT_COORD_PIX(j, w) - w->board.htinc / 2; XCopyArea(XtDisplay(w), w->board.board, w->board.last, w->board.gc, x, y, w->board.wdinc, w->board.htinc, 0, 0); XDrawRectangle(XtDisplay(w), w->board.board, w->board.gc, x, y, w->board.wdinc - 1, w->board.htinc - 1); w->board.curhx = i; w->board.curhy = j; BWUpdatePos(w, i, j); } void BWPutPiece(w, i, j, p) BoardWidget w; int i, j; BWPiece p; { Dimension x, y; Display *theDisplay = XtDisplay(w); #ifdef DEBUG fprintf(stderr, "PutPiece called %d %d %d\n", i, j, p); #endif BWUnhighlight(w); x = WD_COORD_PIX(i, w) - w->board.wdinc / 2; y = HT_COORD_PIX(j, w) - w->board.htinc / 2; switch( p ) { case Empty: XCopyArea(theDisplay, w->board.backing, w->board.board, w->board.gc, x, y, w->board.wdinc, w->board.htinc, x, y); break; case Black: XCopyArea(theDisplay, w->board.black, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); break; case White: XCopyArea(theDisplay, w->board.white, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); break; case Dame: XCopyArea(theDisplay, w->board.dame, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); break; case WhiteTerritory: XCopyArea(theDisplay, w->board.wterr, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); break; case BlackTerritory: XCopyArea(theDisplay, w->board.bterr, w->board.board, w->board.gc, 0, 0, w->board.wdinc, w->board.htinc, x, y); break; default: XtAppWarning(app_context, "BWPutPiece: Not a valid Piece"); return; break; } w->board.pieces[i][j].p = p; w->board.pieces[i][j].m = NoMark; w->board.pieces[i][j].l = '\0'; BWUpdatePos(w, i, j); } void BWSetMark(w, i, j, m) BoardWidget w; int i, j; BWMark m; { Dimension deltax, deltay; Dimension x, y; long GCMask; XGCValues GCVals; GC tmpgc; BWPiece p; XPoint lines[5]; int linecnt = 0; #ifdef DEBUG fprintf(stderr, "SetMark called %d %d %d\n", i, j, m); #endif p = GET_PIECE(w, i, j); GCMask = GCForeground | GCBackground; if( p == Black ) { GCVals.foreground = w->core.background_pixel; GCVals.background = w->board.foreground; } else { GCVals.background = w->core.background_pixel; GCVals.foreground = w->board.foreground; } tmpgc = XtGetGC( w, GCMask, &GCVals ); x = WD_COORD_PIX(i, w); y = HT_COORD_PIX(j, w); switch( m ) { case NoMark: break; case SquareMark: deltax = w->board.wdinc / 4; deltay = w->board.htinc / 4; lines[linecnt].x = x - deltax; lines[linecnt].y = y - deltay; linecnt++; lines[linecnt].x = x + deltax; lines[linecnt].y = y - deltay; linecnt++; lines[linecnt].x = x + deltax; lines[linecnt].y = y + deltay; linecnt++; lines[linecnt].x = x - deltax; lines[linecnt].y = y + deltay; linecnt++; lines[linecnt].x = x - deltax; lines[linecnt].y = y - deltay; linecnt++; break; case TriangleMark: deltax = w->board.wdinc / 3; deltay = w->board.htinc / 3; lines[linecnt].x = x; lines[linecnt].y = y - deltay; linecnt++; lines[linecnt].x = x + deltax; lines[linecnt].y = y + deltay; linecnt++; lines[linecnt].x = x - deltax; lines[linecnt].y = y + deltay; linecnt++; lines[linecnt].x = x; lines[linecnt].y = y - deltay; linecnt++; break; case DiamondMark: deltax = w->board.wdinc / 3; deltay = w->board.htinc / 3; lines[linecnt].x = x; lines[linecnt].y = y - deltay; linecnt++; lines[linecnt].x = x + deltax; lines[linecnt].y = y; linecnt++; lines[linecnt].x = x; lines[linecnt].y = y + deltay; linecnt++; lines[linecnt].x = x - deltax; lines[linecnt].y = y; linecnt++; lines[linecnt].x = x; lines[linecnt].y = y - deltay; linecnt++; break; case XMark: XtAppWarning(app_context, "BWSetMark: XMark, not implemented."); return; break; case HLineMark: XtAppWarning(app_context, "BWSetMark: HLineMark, not implemented."); return; break; case VLineMark: XtAppWarning(app_context, "BWSetMark: VLineMark, not implemented."); return; break; default: XtAppWarning(app_context, "BWSetMark: Not a valid Mark"); return; break; } w->board.pieces[i][j].m = m; BWUnhighlight(w); XDrawLines(XtDisplay(w), w->board.board, tmpgc, lines, linecnt, CoordModeOrigin); XtReleaseGC(w, tmpgc); BWUpdatePos(w, i, j); } BWPiece BWGetPiece(w, i, j) BoardWidget w; int i, j; { #ifdef DEBUG fprintf(stderr, "GetPiece called %d %d\n", i, j); #endif return GET_PIECE(w, i, j); } void BWSetLetter(w, i, j, c) BoardWidget w; int i, j; char c; { BWPiece p; Dimension x, y; #ifdef DEBUG fprintf(stderr, "SetLetter called %d %d %c\n", i, j, c); #endif p = GET_PIECE(w, i, j); if (p != Empty && isalpha(c)) { XtAppWarning(app_context, "Letters on non-empty spaces not supported"); return; } #if 0 x = WD_COORD_PIX(i, w) + w->board.wdinc / 4; y = HT_COORD_PIX(j, w) + w->board.htinc / 4; #else x = WD_COORD_PIX(i, w); y = HT_COORD_PIX(j, w); #endif w->board.pieces[i][j].l = c; BWUnhighlight(w); if (isalpha(c)) PutCStr(w, &c, 1, x, y, w->board.board); BWUpdatePos(w, i, j); } SHAR_EOF fi if test -f 'Board.h' then echo shar: "will not over-write existing file 'Board.h'" else cat << \SHAR_EOF > 'Board.h' /* Board.h * * Copyright (c) 1992 by Tim Casey and Chien-Min Wang. * All rights reserved. */ #ifndef Board_h #define Board_h #define INDEX_TO_CHAR(n) ( (n) >= 8 ? (n) + 'A' + 1 : (n) + 'A') #define XtNboardFont "boardFont" #define XtCBoardFont "BoardFont" #define XtNboardSize "boardSize" #define XtCBoardSize "BoardSize" #define XtNdoText "doText" #define XtCDoText "DoText" #define XtNboardColor "boardColor" #define XtCBoardColor "BoardColor" #define XtNbuttonDown "buttonDown" #define XtCButtonDown "ButtonDown" #define XtNbuttonUp "buttonUp" #define XtCButtonUp "ButtonUp" #define XtNkeyUp "keyUp" #define XtCKeyUp "KeyUp" #define XtNkeyDown "keyDown" #define XtCKeyDown "KeyDown" typedef struct _BoardClassRec *BoardWidgetClass; typedef struct _BoardRec *BoardWidget; typedef enum { Empty, Black, White, Dame, BlackTerritory, WhiteTerritory } BWPiece; typedef enum { NoMark, SquareMark, TriangleMark, DiamondMark, XMark, HLineMark, VLineMark } BWMark; typedef struct { BWPiece p; BWMark m; char l; } BWIntPiece; extern WidgetClass boardWidgetClass; extern Pixmap BoardPix(/*w*/); extern GC BoardGC(/*w*/); extern void GetBoardDimensions(/* w, *i, *j */); extern void BWUpdateBoard( /* w */ ); extern void BWUpdatePos( /* w, i, j, p */ ); extern void BWClearBoard(/*w*/); extern void BWReset( /* w */ ); extern void BWHighlightPiece( /* w, i, j */ ); extern void BWUnighlight( /* w */ ); extern void BWPutPiece( /* w, i, j, p */ ); extern void BWSetLetter( /* w, i, j, p */ ); extern void BWSetMark( /* w, i, j, p */ ); extern BWPiece BWGetPiece( /* w, i, j */ ); extern int resized; #endif Board_h SHAR_EOF fi if test -f 'BoardP.h' then echo shar: "will not over-write existing file 'BoardP.h'" else cat << \SHAR_EOF > 'BoardP.h' /* BoardP.h * * Copyright (c) 1992 by Tim Casey and Chien-Min Wang. * All rights reserved. */ #ifndef BoardP_h #define BoardP_h #include "Board.h" #include <X11/CoreP.h> #define MAX_SIZE 21 #define X_ARC(n) (n * 64) typedef struct { XtWidgetProc buttonProc; XtTranslations translations; } BoardClassPart; typedef struct _BoardClassRec { CoreClassPart core_class; BoardClassPart board_class; } BoardClassRec; extern BoardClassRec boardClassRec; typedef struct { /* resources */ Pixel foreground, boardcolor; XFontStruct *font; XtCallbackList Bup, Bdown, Kdown; int boardsize; /* private state info */ Pixmap board, backing, white, black, dame, bterr, wterr, last, bhi, whi; GC gc; int htinc, wdinc, length; BWIntPiece pieces[19][19]; int curhx, curhy; } BoardPart; typedef struct _BoardRec { CorePart core; BoardPart board; } BoardRec; #endif BoardP_h SHAR_EOF fi if test -f 'DirMgr.c' then echo shar: "will not over-write existing file 'DirMgr.c'" else cat << \SHAR_EOF > 'DirMgr.c' /**************************************************************************** DirMgr.c This file contains the C code to implement the DirectoryMgr system. This system is intended to manage filtered and sorted directory lists. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #include "DirMgr.h" #ifndef NO_REGEXP #include "RegExp.h" #endif #define DIR_MGR_FSM_SIZE 1024 /*---------------------------------------------------------------------------* S I M P L E I N T E R F A C E *---------------------------------------------------------------------------*/ DirectoryMgr *DirectoryMgrSimpleOpen(path,sort_type,pattern) char *path; int sort_type; char *pattern; { DirectoryMgr *dm; PFI f_func,s_func; char *f_data; if (pattern == NULL) pattern = "*"; if (!DirectoryMgrSimpleFilterFunc(pattern,&f_func,&f_data)) { return(NULL); } if (!DirectoryMgrSimpleSortingFunc(sort_type,&s_func)) { free(f_data); return(NULL); } dm = DirectoryMgrOpen(path,s_func,f_func,f_data,TRUE); return(dm); } /* End DirectoryMgrSimpleOpen */ int DirectoryMgrSimpleRefilter(dm,pattern) DirectoryMgr *dm; char *pattern; { PFI f_func; char *f_data; if (!DirectoryMgrSimpleFilterFunc(pattern,&f_func,&f_data)) { return(FALSE); } DirectoryMgrRefilter(dm,f_func,f_data,TRUE); return(TRUE); } /* End DirectoryMgrSimpleRefilter */ int DirectoryMgrSimpleResort(dm,sort_type) DirectoryMgr *dm; int sort_type; { PFI c_func; if (!DirectoryMgrSimpleSortingFunc(sort_type,&c_func)) { return(FALSE); } DirectoryMgrResort(dm,c_func); return(TRUE); } /* End DirectoryMgrSimpleResort */ /*---------------------------------------------------------------------------* N O R M A L I N T E R F A C E *---------------------------------------------------------------------------*/ DirectoryMgr *DirectoryMgrOpen(path,c_func,f_func,f_data,free_data) char *path; PFI c_func,f_func; char *f_data; int free_data; { DirectoryMgr *dm; dm = (DirectoryMgr *)calloc(1,sizeof(DirectoryMgr)); if (dm == NULL) { if (free_data && f_data) free(f_data); return(NULL); } if (DirectoryOpen(path,DirectoryMgrDir(dm)) == FALSE) { free(dm); if (free_data && f_data) free(f_data); return(NULL); } DirectoryMgrCompFunc(dm) = c_func; DirectoryMgrRefilter(dm,f_func,f_data,free_data); return(dm); } /* End DirectoryMgrOpen */ void DirectoryMgrClose(dm) DirectoryMgr *dm; { free(DirectoryMgrData(dm)); free(DirectoryMgrSortedPtrs(dm)); if (DirectoryMgrFilterData(dm) && DirectoryMgrFreeFilterData(dm)) { free(DirectoryMgrFilterData(dm)); } DirectoryClose(DirectoryMgrDir(dm)); free(dm); } /* End DirectoryMgrClose */ int DirectoryMgrRefilter(dm,f_func,f_data,f_free) DirectoryMgr *dm; PFI f_func; char *f_data; int f_free; { if (DirectoryMgrFilterData(dm) && DirectoryMgrFreeFilterData(dm)) { free(DirectoryMgrFilterData(dm)); } DirectoryMgrFilterFunc(dm) = f_func; DirectoryMgrFilterData(dm) = f_data; DirectoryMgrFreeFilterData(dm) = f_free; DirectoryMgrRefresh(dm); } /* End DirectoryMgrRefilter */ int DirectoryMgrRefresh(dm) DirectoryMgr *dm; { int err,data_size,ptrs_size,i; DirEntryCons *head,*tail,*cons; DirEntry *dm_data,**dm_ptrs; PFI f_func; char *f_data; DirectoryMgrTotalCount(dm) = 0; DirectoryMgrFilteredCount(dm) = 0; DirectoryRestart(DirectoryMgrDir(dm)); if (DirectoryMgrData(dm)) free(DirectoryMgrData(dm)); if (DirectoryMgrSortedPtrs(dm)) free(DirectoryMgrSortedPtrs(dm)); head = NULL; f_func = DirectoryMgrFilterFunc(dm); f_data = DirectoryMgrFilterData(dm); while (1) { cons = (DirEntryCons *)malloc(sizeof(DirEntryCons)); if (cons == NULL) { fprintf(stderr, "DirectoryMgrRefresh: Can't Alloc Cons\n"); exit(-1); } err = DirectoryReadNextEntry(DirectoryMgrDir(dm), &(cons->dir_entry)); if (err == FALSE) { free(cons); break; } ++ DirectoryMgrTotalCount(dm); if ((f_func == NULL) || (f_func && f_func(&(cons->dir_entry),f_data))) { cons->next = NULL; if (head == NULL) head = cons; else tail->next = cons; tail = cons; ++ DirectoryMgrFilteredCount(dm); } else /* Filter Failed */ { free(cons); } } data_size = sizeof(DirEntry) * DirectoryMgrFilteredCount(dm); ptrs_size = sizeof(DirEntry *) * DirectoryMgrFilteredCount(dm); dm_data = (DirEntry *)malloc(data_size); dm_ptrs = (DirEntry **)malloc(ptrs_size); if ((dm_data == NULL) || (dm_ptrs == NULL)) { fprintf(stderr,"DirectoryMgrRefresh: Out of memory\n"); exit(1); } DirectoryMgrData(dm) = dm_data; DirectoryMgrSortedPtrs(dm) = dm_ptrs; for (i = 0; i < DirectoryMgrFilteredCount(dm); i++) { DirectoryMgrData(dm)[i] = head->dir_entry; DirectoryMgrSortedPtrs(dm)[i] = &(DirectoryMgrData(dm)[i]); cons = head->next; free(head); head = cons; } DirectoryMgrResort(dm,DirectoryMgrCompFunc(dm)); DirectoryMgrRestart(dm); return(TRUE); } /* End DirectoryMgrRefresh */ void DirectoryMgrResort(dm,c_func) DirectoryMgr *dm; PFI c_func; { DirectoryMgrCompFunc(dm) = c_func; if (c_func != NULL) { qsort(DirectoryMgrSortedPtrs(dm),DirectoryMgrFilteredCount(dm), sizeof(DirEntry *),DirectoryMgrCompFunc(dm)); } DirectoryMgrRestart(dm); } /* End DirectoryMgrResort */ /*---------------------------------------------------------------------------* I T E R A T I O N C O M M A N D S *---------------------------------------------------------------------------*/ int DirectoryMgrGotoItem(dm,i) DirectoryMgr *dm; int i; { if (i < 0 || i >= DirectoryMgrFilteredCount(dm)) return(FALSE); DirectoryMgrCurrentIndex(dm) = i; return(TRUE); } /* End DirectoryMgrGotoItem */ int DirectoryMgrGotoNamedItem(dm,name) DirectoryMgr *dm; char *name; { int i; DirEntry *entry; for (i = 0; i < DirectoryMgrFilteredCount(dm); i++) { entry = DirectoryMgrSortedPtrs(dm)[i]; if (strcmp(DirEntryFileName(entry),name) == 0) { DirectoryMgrCurrentIndex(dm) = i; return(TRUE); } } return(FALSE); } /* End DirectoryMgrGotoNamedItem */ void DirectoryMgrRestart(dm) DirectoryMgr *dm; { DirectoryMgrCurrentIndex(dm) = 0; } /* End DirectoryMgrRestart */ DirEntry *DirectoryMgrCurrentEntry(dm) DirectoryMgr *dm; { int index; index = DirectoryMgrCurrentIndex(dm); if (index < 0 || index >= DirectoryMgrFilteredCount(dm)) return(NULL); return(DirectoryMgrSortedPtrs(dm)[index]); } /* End DirectoryMgrCurrentEntry */ DirEntry *DirectoryMgrNextEntry(dm) DirectoryMgr *dm; { int index; index = DirectoryMgrCurrentIndex(dm); if (index >= DirectoryMgrFilteredCount(dm)) return(NULL); ++ DirectoryMgrCurrentIndex(dm); return(DirectoryMgrSortedPtrs(dm)[index]); } /* End DirectoryMgrNextEntry */ DirEntry *DirectoryMgrPrevEntry(dm) DirectoryMgr *dm; { int index; index = DirectoryMgrCurrentIndex(dm) - 1; if (index < 0) return(NULL); -- DirectoryMgrCurrentIndex(dm); return(DirectoryMgrSortedPtrs(dm)[index]); } /* End DirectoryMgrPrevEntry */ /*---------------------------------------------------------------------------* U T I L I T Y F U N C T I O N S *---------------------------------------------------------------------------*/ int DirectoryMgrSimpleFilterFunc(pattern,ff_ptr,fd_ptr) char *pattern; PFI *ff_ptr; char **fd_ptr; { #ifndef NO_REGEXP char regexp[2048]; *ff_ptr = DirectoryMgrFilterName; *fd_ptr = (char *)malloc(sizeof(char) * DIR_MGR_FSM_SIZE); if (*fd_ptr == NULL) return(FALSE); RegExpPatternToRegExp(pattern,regexp); RegExpCompile(regexp,*fd_ptr,DIR_MGR_FSM_SIZE); #endif return(TRUE); } /* End DirectoryMgrSimpleFilterFunc */ int DirectoryMgrSimpleSortingFunc(sort_type,sf_ptr) int sort_type; PFI *sf_ptr; { *sf_ptr = NULL; switch (sort_type) { case DIR_MGR_SORT_NONE: break; case DIR_MGR_SORT_NAME: *sf_ptr = DirectoryMgrCompareName; break; case DIR_MGR_SORT_SIZE_ASCENDING: *sf_ptr = DirectoryMgrCompareSizeAscending; break; case DIR_MGR_SORT_SIZE_DESCENDING: *sf_ptr = DirectoryMgrCompareSizeDescending; break; case DIR_MGR_SORT_NAME_DIRS_FIRST: *sf_ptr = DirectoryMgrCompareNameDirsFirst; break; case DIR_MGR_SORT_ACCESS_ASCENDING: *sf_ptr = DirectoryMgrCompareLastAccessAscending; break; case DIR_MGR_SORT_ACCESS_DESCENDING: *sf_ptr = DirectoryMgrCompareLastAccessDescending; break; default: fprintf(stderr,"Bad sort type %d\n",sort_type); return(FALSE); } return(TRUE); } /* End DirectoryMgrSimpleSortingFunc */ /*---------------------------------------------------------------------------* S O R T I N G R O U T I N E S *---------------------------------------------------------------------------*/ int DirectoryMgrCompareName(e1p,e2p) DirEntry **e1p,**e2p; { return(strcmp(DirEntryFileName(*e1p),DirEntryFileName(*e2p))); } /* End DirectoryMgrCompareName */ int DirectoryMgrCompareNameDirsFirst(e1p,e2p) DirEntry **e1p,**e2p; { if (DirEntryLeadsToDir(*e1p)) { if (!DirEntryLeadsToDir(*e2p)) return(-1); } else if (DirEntryLeadsToDir(*e2p)) { return(1); } return(strcmp(DirEntryFileName(*e1p),DirEntryFileName(*e2p))); } /* End DirectoryMgrCompareNameDirsFirst */ int DirectoryMgrCompareSizeAscending(e1p,e2p) DirEntry **e1p,**e2p; { if (DirEntryFileSize(*e1p) < DirEntryFileSize(*e2p)) return (-1); else if (DirEntryFileSize(*e1p) == DirEntryFileSize(*e2p)) return (0); else return (1); } /* End DirectoryMgrCompareSizeAscending */ int DirectoryMgrCompareSizeDescending(e1p,e2p) DirEntry **e1p,**e2p; { if (DirEntryFileSize(*e1p) > DirEntryFileSize(*e2p)) return (-1); else if (DirEntryFileSize(*e1p) == DirEntryFileSize(*e2p)) return (0); else return (1); } /* End DirectoryMgrCompareSizeDescending */ int DirectoryMgrCompareLastAccessAscending(e1p,e2p) DirEntry **e1p,**e2p; { return((long)DirEntryLastAccess(*e1p) > (long)DirEntryLastAccess(*e2p)); } /* End DirectoryMgrCompareLastAccessAscending */ int DirectoryMgrCompareLastAccessDescending(e1p,e2p) DirEntry **e1p,**e2p; { return((long)DirEntryLastAccess(*e1p) < (long)DirEntryLastAccess(*e2p)); } /* End DirectoryMgrCompareLastAccessDescending */ /*---------------------------------------------------------------------------* F I L T E R R O U T I N E S *---------------------------------------------------------------------------*/ int DirectoryMgrFilterName(de,fsm) DirEntry *de; char *fsm; { #ifndef NO_REGEXP return(RegExpMatch(DirEntryFileName(de),fsm)); #else return(TRUE); #endif } /* End DirectoryMgrFilterName */ SHAR_EOF fi if test -f 'DirMgr.h' then echo shar: "will not over-write existing file 'DirMgr.h'" else cat << \SHAR_EOF > 'DirMgr.h' /**************************************************************************** DirMgr.h This file contains the C declarations and definitions for the DirectoryMgr system. This system is intended to managed filtered and sorted directory lists. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _DIRECTORY_MGR_H_ #define _DIRECTORY_MGR_H_ #include "Directory.h" /*---------------------------------------------------------------------------* Simple DirectoryMgr Interface DirectoryMgrSimpleOpen(); DirectoryMgrSimpleRefilter(); DirectoryMgrSimpleResort(); Standard DirectoryMgr Interface DirectoryMgrOpen(); DirectoryMgrClose(); DirectoryMgrRefilter(); DirectoryMgrRefresh(); DirectoryMgrResort(); Moving Around Items DirectoryMgrGotoItem(); DirectoryMgrGotoNamedItem(); DirectoryMgrRestart(); DirectoryMgrGetIndex(); DirectoryMgrCurrentEntry(); DirectoryMgrNextEntry(); DirectoryMgrPrevEntry(); Utility Functions DirectoryMgrSimpleFilterFunc(); DirectoryMgrSimpleSortingFunc(); Comparison Functions DirectoryMgrCompareName(); DirectoryMgrCompareSizeAscending(); DirectoryMgrCompareSizeDescending(); Macros DirectoryMgrDir(); DirectoryMgrData(); DirectoryMgrSortedPtrs(); DirectoryMgrFilterFunc(); DirectoryMgrCompFunc(); DirectoryMgrFilterData(); DirectoryMgrFreeFilterData(); DirectoryMgrTotalCount(); DirectoryMgrFilteredCount(); DirectoryMgrCurrentIndex(); *---------------------------------------------------------------------------*/ #ifndef PFI typedef int (*PFI)(); #endif typedef struct entry_cons { DIR_ENTRY dir_entry; struct entry_cons *next; } DIR_ENTRY_CONS; typedef DIR_ENTRY_CONS DirEntryCons; typedef struct { DIRECTORY dir; DIR_ENTRY *data; DIR_ENTRY **sorted_ptrs; int total_count; int filtered_count; PFI filter_func; char *filter_data; int free_filter_data; PFI comp_func; int current_index; } DIRECTORY_MGR; typedef DIRECTORY_MGR DirectoryMgr; #define DIR_MGR_SORT_NONE 0 #define DIR_MGR_SORT_NAME 1 #define DIR_MGR_SORT_NAME_DIRS_FIRST 2 #define DIR_MGR_SORT_SIZE_ASCENDING 3 #define DIR_MGR_SORT_SIZE_DESCENDING 4 #define DIR_MGR_SORT_ACCESS_ASCENDING 5 #define DIR_MGR_SORT_ACCESS_DESCENDING 6 #define DirectoryMgrDir(dm) (&((dm)->dir)) #define DirectoryMgrData(dm) ((dm)->data) #define DirectoryMgrSortedPtrs(dm) ((dm)->sorted_ptrs) #define DirectoryMgrFilterFunc(dm) ((dm)->filter_func) #define DirectoryMgrCompFunc(dm) ((dm)->comp_func) #define DirectoryMgrFilterData(dm) ((dm)->filter_data) #define DirectoryMgrFreeFilterData(dm) ((dm)->free_filter_data) #define DirectoryMgrTotalCount(dm) ((dm)->total_count) #define DirectoryMgrFilteredCount(dm) ((dm)->filtered_count) #define DirectoryMgrCurrentIndex(dm) ((dm)->current_index) #if (!NeedFunctionPrototypes) DirectoryMgr * DirectoryMgrSimpleOpen(); int DirectoryMgrSimpleRefilter(); int DirectoryMgrSimpleResort(); DirectoryMgr * DirectoryMgrOpen(); void DirectoryMgrClose(); int DirectoryMgrRefilter(); int DirectoryMgrRefresh(); void DirectoryMgrResort(); int DirectoryMgrGotoItem(); int DirectoryMgrGotoNamedItem(); void DirectoryMgrRestart(); int DirectoryMgrGetIndex(); DirEntry * DirectoryMgrCurrentEntry(); DirEntry * DirectoryMgrNextEntry(); DirEntry * DirectoryMgrPrevEntry(); int DirectoryMgrSimpleFilterFunc(); int DirectoryMgrSimpleSortingFunc(); int DirectoryMgrCompareName(); int DirectoryMgrCompareNameDirsFirst(); int DirectoryMgrCompareSizeAscending(); int DirectoryMgrCompareSizeDescending(); int DirectoryMgrCompareLastAccessAscending(); int DirectoryMgrCompareLastAccessDescending(); int DirectoryMgrFilterName(); #else DirectoryMgr * DirectoryMgrSimpleOpen(char *path, int sort_type, char *pattern); int DirectoryMgrSimpleRefilter(DirectoryMgr *dm, char *pattern); int DirectoryMgrSimpleResort(DirectoryMgr *dm, int sort_type); DirectoryMgr * DirectoryMgrOpen(char *path, PFI c_func, PFI f_func, char *f_data, int free_data); void DirectoryMgrClose(DirectoryMgr *dm); int DirectoryMgrRefilter(DirectoryMgr *dm, PFI f_func, char *f_data, int f_free); int DirectoryMgrRefresh(DirectoryMgr *dm); void DirectoryMgrResort(DirectoryMgr *dm, PFI c_func); int DirectoryMgrGotoItem(DirectoryMgr *dm, int i); int DirectoryMgrGotoNamedItem(DirectoryMgr *dm, char *name); void DirectoryMgrRestart(DirectoryMgr *dm); DirEntry * DirectoryMgrCurrentEntry(DirectoryMgr *dm); DirEntry * DirectoryMgrNextEntry(DirectoryMgr *dm); DirEntry * DirectoryMgrPrevEntry(DirectoryMgr *dm); int DirectoryMgrSimpleFilterFunc(char *pattern, PFI *ff_ptr, char **fd_ptr); int DirectoryMgrSimpleSortingFunc(int sort_type, PFI *sf_ptr); int DirectoryMgrCompareName(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrCompareNameDirsFirst(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrCompareSizeAscending(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrCompareSizeDescending(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrCompareLastAccessAscending(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrCompareLastAccessDescending(DirEntry **e1p, DirEntry **e2p); int DirectoryMgrFilterName(DirEntry *de, char *fsm); #endif #endif SHAR_EOF fi if test -f 'Directory.c' then echo shar: "will not over-write existing file 'Directory.c'" else cat << \SHAR_EOF > 'Directory.c' /**************************************************************************** Directory.c This file contains the C code that implements the directory iteration and file information subsystem. This code is intended to be used as a convenient, machine independent interface to iterate through the contents of a directory. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #include "Directory.h" #include "RegExp.h" /*--------------------------------------------------------------------------* L O W L E V E L D I R E C T O R Y I N T E R F A C E *--------------------------------------------------------------------------*/ int DirectoryOpen(dir_name,dp) char *dir_name; Directory *dp; { DirectoryDir(dp) = opendir(dir_name); if (DirectoryDir(dp) == NULL) return(FALSE); if (DirectoryPathExpand(dir_name,DirectoryPath(dp)) == NULL) { closedir(DirectoryDir(dp)); return(FALSE); } return(TRUE); } /* End DirectoryOpen */ void DirectoryRestart(dp) Directory *dp; { rewinddir(DirectoryDir(dp)); } /* End DirectoryRestart */ void DirectoryClose(dp) Directory *dp; { closedir(DirectoryDir(dp)); } /* End DirectoryClose */ long DirectoryTellPosition(dp) Directory *dp; { return(telldir(DirectoryDir(dp))); } /* End DirectoryTellPosition */ void DirectorySetPosition(dp,pos) Directory *dp; long pos; { seekdir(dp,pos); } /* End DirectorySetPosition */ int DirectoryReadNextEntry(dp,de) Directory *dp; DirEntry *de; { u_short orig_file_type; static struct dirent *_ep; static struct stat _lstats,_stats; char full_path[MAXPATHLEN + 2]; _ep = readdir(DirectoryDir(dp)); if (_ep == NULL) return(FALSE); strcpy(DirEntryFileName(de),_ep->d_name); strcpy(full_path,DirectoryPath(dp)); strcat(full_path,DirEntryFileName(de)); if (lstat(full_path,&_lstats) != 0) return(FALSE); orig_file_type = _lstats.st_mode & S_IFMT; switch (orig_file_type) { case S_IFDIR: DirEntryType(de) = F_TYPE_DIR; break; case S_IFREG: DirEntryType(de) = F_TYPE_FILE; break; case S_IFCHR: DirEntryType(de) = F_TYPE_CHAR_SPECIAL; break; case S_IFBLK: DirEntryType(de) = F_TYPE_BLOCK_SPECIAL; break; case S_IFLNK: DirEntryType(de) = F_TYPE_SYM_LINK; break; case S_IFSOCK: DirEntryType(de) = F_TYPE_SOCKET; break; #ifdef S_IFIFO case S_IFIFO: DirEntryType(de) = F_TYPE_FIFO; break; #endif default: DirEntryType(de) = orig_file_type; break; } DirEntryIsBrokenLink(de) = FALSE; DirEntryIsDirectoryLink(de) = FALSE; if (DirEntryIsSymLink(de)) /* Symbolic Link */ { if (stat(full_path,&_stats) != 0) /* Can't Stat File */ { DirEntryIsBrokenLink(de) = TRUE; _stats = _lstats; } else /* Link Not Broken */ { #ifdef SLOW_DIRLINK_TEST char temp_path[MAXPATHLEN + 2]; if (DirectoryPathExpand(full_path,temp_path) != NULL) { #else if ((_stats.st_mode & S_IFMT) == S_IFDIR) { #endif DirEntryIsDirectoryLink(de) = TRUE; } } } else /* Not Symbolic Link */ { _stats = _lstats; } FileInfoOrigMode(DirEntrySelfInfo(de)) = _lstats.st_mode; FileInfoProt(DirEntrySelfInfo(de)) = _lstats.st_mode & 0777; FileInfoUserID(DirEntrySelfInfo(de)) = _lstats.st_uid; FileInfoGroupID(DirEntrySelfInfo(de)) = _lstats.st_gid; FileInfoFileSize(DirEntrySelfInfo(de)) = _lstats.st_size; FileInfoLastAccess(DirEntrySelfInfo(de)) = _lstats.st_atime; FileInfoLastModify(DirEntrySelfInfo(de)) = _lstats.st_mtime; FileInfoLastStatusChange(DirEntrySelfInfo(de)) = _lstats.st_ctime; FileInfoOrigMode(DirEntryActualInfo(de)) = _stats.st_mode; FileInfoProt(DirEntryActualInfo(de)) = _stats.st_mode & 0777; FileInfoUserID(DirEntryActualInfo(de)) = _stats.st_uid; FileInfoGroupID(DirEntryActualInfo(de)) = _stats.st_gid; FileInfoFileSize(DirEntryActualInfo(de)) = _stats.st_size; FileInfoLastAccess(DirEntryActualInfo(de)) = _stats.st_atime; FileInfoLastModify(DirEntryActualInfo(de)) = _stats.st_mtime; FileInfoLastStatusChange(DirEntryActualInfo(de)) = _stats.st_ctime; return(TRUE); } /* End DirectoryReadNextEntry */ char *DirectoryPathExpand(old_path,new_path) char *old_path,*new_path; { register char *p; char path[MAXPATHLEN + 2]; if (getwd(path) == NULL) return(NULL); if (chdir(old_path) != 0) return(NULL); if (getwd(new_path) == NULL) strcpy(new_path,old_path); if (chdir(path) != 0) return(NULL); for (p = new_path; *p != '\0'; p++); if ((p != new_path) && *(p - 1) != '/') { *p++ = '/'; *p = '\0'; } return(new_path); } /* End DirectoryPathExpand */ /*---------------------------------------------------------------------------* D I R E C T O R Y E N T R Y R O U T I N E S *---------------------------------------------------------------------------*/ void DirEntryDump(fp,de) FILE *fp; DirEntry *de; { fprintf(fp,"%20s, Size %7d, Prot %3o\n", DirEntryFileName(de),DirEntryFileSize(de),DirEntryProt(de)); } /* End DirEntryDump */ SHAR_EOF fi if test -f 'Directory.h' then echo shar: "will not over-write existing file 'Directory.h'" else cat << \SHAR_EOF > 'Directory.h' /**************************************************************************** Directory.h This file contains the C definitions and declarations for the Directory.c directory iteration code. This code is intended to be used as a convenient, machine independent interface to iterate through the contents of a directory. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _DIRECTORY_H_ #define _DIRECTORY_H_ #include <stdio.h> #include <string.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #ifdef SYSV #define getwd(path) getcwd(path, MAXPATHLEN) #endif #ifndef NO_DIRENT #include <dirent.h> #else #include <sys/dir.h> #define dirent direct #endif #ifndef _SYS_NAME_MAX #ifndef MAXNAMLEN ERROR, ONE OF THESE MUST BE DEFINED #else #define MAX_NAME_LENGTH MAXNAMLEN #endif #else #define MAX_NAME_LENGTH _SYS_NAME_MAX #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define PERM_READ 4 #define PERM_WRITE 2 #define PERM_EXECUTE 1 #define F_TYPE_DIR 1 #define F_TYPE_FILE 2 #define F_TYPE_CHAR_SPECIAL 3 #define F_TYPE_BLOCK_SPECIAL 4 #define F_TYPE_SYM_LINK 5 #define F_TYPE_SOCKET 6 #define F_TYPE_FIFO 7 /*--------------------------------------------------------------------------* D A T A T Y P E A C C E S S M A C R O S *--------------------------------------------------------------------------*/ /* Directory: Directory Iterator */ #define DirectoryDir(dp) ((dp)->filep) #define DirectoryPath(dp) ((dp)->path) /* FileInfo: Information About A File Or Link */ #define FileInfoProt(fi) ((fi)->protections) #define FileInfoOrigMode(fi) ((fi)->orig_mode) #define FileInfoUserID(fi) ((fi)->user_id) #define FileInfoGroupID(fi) ((fi)->group_id) #define FileInfoFileSize(fi) ((fi)->size) #define FileInfoLastAccess(fi) ((fi)->last_access) #define FileInfoLastModify(fi) ((fi)->last_modify) #define FileInfoLastStatusChange(fi) ((fi)->last_status_change) #define FIProt(fi) FileInfoProt(fi) #define FIOrigMode(fi) FileInfoOrigMode(fi) #define FIUserID(fi) FileInfoUserID(fi) #define FIGroupID(fi) FileInfoGroupID(fi) #define FIFileSize(fi) FileInfoFileSize(fi) #define FILastAccess(fi) FileInfoLastAccess(fi) #define FILastModify(fi) FileInfoLastModify(fi) #define FILastStatusChange(fi) FileInfoLastStatusChange(fi) /* FType: File Type Macros */ #define FTypeIsDir(ft) ((ft) == F_TYPE_DIR) #define FTypeIsFile(ft) ((ft) == F_TYPE_FILE) #define FTypeIsCharSpecial(ft) ((ft) == F_TYPE_CHAR_SPECIAL) #define FTypeIsBlockSpecial(ft) ((ft) == F_TYPE_BLOCK_SPECIAL) #define FTypeIsSymLink(ft) ((ft) == F_TYPE_SYM_LINK) #define FTypeIsSocket(ft) ((ft) == F_TYPE_SOCKET) #define FTypeIsFifo(ft) ((ft) == F_TYPE_FIFO) /* DirEntry: Information About A Item In A Directory */ #define DirEntryFileName(fi) ((fi)->filename) #define DirEntryType(fi) ((fi)->file_type) #define DirEntrySelfInfo(fi) (&((fi)->self_info)) #define DirEntryActualInfo(fi) (&((fi)->actual_info)) #define DirEntryIsBrokenLink(fi) ((fi)->broken_link) #define DirEntryIsDirectoryLink(fi) ((fi)->directory_link) #define DirEntryIsDir(fi) (FTypeIsDir(DirEntryType(fi))) #define DirEntryIsFile(fi) (FTypeIsFile(DirEntryType(fi))) #define DirEntryIsCharSpecial(fi) (FTypeIsCharSpecial(DirEntryType(fi))) #define DirEntryIsBlockSpecial(fi) (FTypeIsBlockSpecial(DirEntryType(fi))) #define DirEntryIsSymLink(fi) (FTypeIsSymLink(DirEntryType(fi))) #define DirEntryIsSocket(fi) (FTypeIsSocket(DirEntryType(fi))) #define DirEntryIsFifo(fi) (FTypeIsFifo(DirEntryType(fi))) #define DirEntryLeadsToDir(fi) (DirEntryIsDir(fi) || \ DirEntryIsDirectoryLink(fi)) #define DirEntryProt(d) FIProt(DirEntrySelfInfo(d)) #define DirEntryOrigMode(d) FIOrigMode(DirEntrySelfInfo(d)) #define DirEntryUserID(d) FIUserID(DirEntrySelfInfo(d)) #define DirEntryGroupID(d) FIGroupID(DirEntrySelfInfo(d)) #define DirEntryFileSize(d) FIFileSize(DirEntrySelfInfo(d)) #define DirEntryLastAccess(d) FILastAccess(DirEntrySelfInfo(d)) #define DirEntryLastModify(d) FILastModify(DirEntrySelfInfo(d)) #define DirEntryLastStatusChange(d) FILastStatusChange(DirEntrySelfInfo(d)) /*--------------------------------------------------------------------------* D A T A T Y P E D E F I N I T I O N S *--------------------------------------------------------------------------*/ /* Directory: Directory Iterator */ typedef struct { DIR *filep; char path[MAXPATHLEN + 2]; } DIRECTORY; typedef DIRECTORY Directory; /* FileInfo: Information About A File Or Link */ typedef struct { short protections; short orig_mode; short user_id; short group_id; long size; time_t last_access; time_t last_modify; time_t last_status_change; } FILE_INFO; typedef FILE_INFO FileInfo; /* DirEntry: Information About A Item In A Directory */ typedef struct { char filename[MAX_NAME_LENGTH + 1]; short file_type; short broken_link; short directory_link; FileInfo self_info; FileInfo actual_info; } DIR_ENTRY; typedef DIR_ENTRY DirEntry; /*--------------------------------------------------------------------------* L O W L E V E L D I R E C T O R Y I N T E R F A C E *--------------------------------------------------------------------------*/ #if (!NeedFunctionPrototypes) int DirectoryOpen(); void DirectoryRestart(); void DirectoryClose(); long DirectoryTellPosition(); void DirectorySetPosition(); int DirectoryReadNextEntry(); char * DirectoryPathExpand(); void DirEntryDump(); #else int DirectoryOpen(char *dir_name, Directory *dp); void DirectoryRestart(Directory *dp); void DirectoryClose(Directory *dp); long DirectoryTellPosition(Directory *dp); void DirectorySetPosition(Directory *dp, long int pos); int DirectoryReadNextEntry(Directory *dp, DirEntry *de); char * DirectoryPathExpand(char *old_path, char *new_path); void DirEntryDump(FILE *fp, DirEntry *de); #endif #endif SHAR_EOF fi if test -f 'FileSel.c' then echo shar: "will not over-write existing file 'FileSel.c'" else cat << \SHAR_EOF > 'FileSel.c' /***************************************************************************** FileSelector.c This file contains the C code for the FileSelector widget, which is intended to be used as a hierarchical Unix file selector box. ******************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #include <stdio.h> #include <X11/Xos.h> #include <X11/Xlib.h> #include <X11/StringDefs.h> #include <X11/IntrinsicP.h> #include <X11/Intrinsic.h> #include <X11/CompositeP.h> #include <X11/Composite.h> #include <X11/cursorfont.h> #include <X11/Xaw/SimpleP.h> #include <X11/Xaw/Simple.h> #include <X11/Xaw/LabelP.h> #include <X11/Xaw/Label.h> #include <X11/Xaw/CommandP.h> #include <X11/Xaw/Command.h> #include <X11/Xaw/AsciiTextP.h> #include <X11/Xaw/AsciiText.h> #include <X11/Xaw/FormP.h> #include <X11/Xaw/Form.h> #include "ScrListP.h" #include "ScrList.h" #include "FileSelP.h" #include "FileSel.h" #ifdef X11R3 #define asciiTextWidgetClass asciiStringWidgetClass #define XawtextEdit XttextEdit #define XtNtype "type" #define XawAsciiString NULL #define XtNautoFill "autoFill" typedef char * XtPointer; #endif #define NO_BUSY_GRAB /*---------------------------------------------------------------------------* D E C L A R A T I O N S *---------------------------------------------------------------------------*/ #define SUPERCLASS (&compositeClassRec) #ifndef abs #define abs(a) ((a) < 0 ? -(a) : (a)) #endif #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) #define XtStrlen(s) ((s) ? strlen(s) : 0) #define StrCopy(s) ((char*)strcpy((char *)malloc((strlen(s)+1) * \ sizeof(char)),((char *)(s)))) #define FSFieldOffset(field) XtOffset(XfwfFileSelectorWidget, \ fileSelector.field) #define CoreFieldOffset(field) XtOffset(Widget,core.field) /*---------------------------------------------------------------------------* I N T E R N A L R O U T I N E S *---------------------------------------------------------------------------*/ #if (!NeedFunctionPrototypes) static void Initialize(); static void Realize(); static void Destroy(); static void Resize(); static Boolean SetValues(); static XtGeometryResult GeometryManager(); static void ChildrenCreate(); static void ChildrenRealize(); static void ChildrenRecalculate(); static void ChildrenUpdate(); static void ButtonUp(); static void ButtonOk(); static void ButtonCancel(); static void ButtonGoto(); static void ButtonSelect(); static char * GetFileBoxText(); static void ClickOnPathList(); static void ClickOnFileList(); static void SelectFileByIndex(); static Boolean SelectFileByName(); static void UnselectAll(); static void NotifySelectionChange(); static void GotoDeepestLegalDirectory(); static void UpdateLists(); static void UpdateTextLines(); static void Chdir(); static void DoBusyCursor(); static void UndoBusyCursor(); static void TextWidgetSetText(); #else static void Initialize(Widget request, Widget new); static void Realize(Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs); static void Destroy(XfwfFileSelectorWidget fsw); static void Resize(Widget gw); static Boolean SetValues(Widget gcurrent, Widget grequest, Widget gnew); static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply); static void ChildrenCreate(XfwfFileSelectorWidget fsw); static void ChildrenRealize(XfwfFileSelectorWidget fsw); static void ChildrenRecalculate(XfwfFileSelectorWidget fsw); static void ChildrenUpdate(XfwfFileSelectorWidget fsw); static void ButtonUp(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void ButtonOk(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void ButtonCancel(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void ButtonGoto(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void ButtonSelect(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static char * GetFileBoxText(XfwfFileSelectorWidget fsw); static void ClickOnPathList(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void ClickOnFileList(Widget w, XfwfFileSelectorWidget fsw, XtPointer call_data); static void SelectFileByIndex(XfwfFileSelectorWidget fsw, int strchr); static Boolean SelectFileByName(XfwfFileSelectorWidget fsw, char *name); static void UnselectAll(XfwfFileSelectorWidget fsw); static void NotifySelectionChange(XfwfFileSelectorWidget fsw); static void GotoDeepestLegalDirectory(XfwfFileSelectorWidget fsw); static void UpdateLists(XfwfFileSelectorWidget fsw); static void UpdateTextLines(XfwfFileSelectorWidget fsw); static void Chdir(XfwfFileSelectorWidget fsw); static void DoBusyCursor(Widget w); static void UndoBusyCursor(Widget w); static void TextWidgetSetText(Widget tw, char *text); #endif /*---------------------------------------------------------------------------* R E S O U R C E I N I T I A L I Z A T I O N *---------------------------------------------------------------------------*/ static XtResource resources[] = { {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), CoreFieldOffset(width), XtRString, "500"}, {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), CoreFieldOffset(height), XtRString, "250"}, {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), CoreFieldOffset(background_pixel), XtRString, "white"}, {XtNokButtonCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), FSFieldOffset(ok_button_callbacks), XtRCallback, NULL}, {XtNcancelButtonCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), FSFieldOffset(cancel_button_callbacks), XtRCallback, NULL}, {XtNselectionChangeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), FSFieldOffset(sel_change_callbacks), XtRCallback, NULL}, {XtNshowOkButton, XtCBoolean, XtRBoolean, sizeof(Boolean), FSFieldOffset(show_ok_button), XtRString, "True"}, {XtNshowCancelButton, XtCBoolean, XtRBoolean, sizeof(Boolean), FSFieldOffset(show_cancel_button), XtRString, "True"}, {XtNflagLinks, XtCBoolean, XtRBoolean, sizeof(Boolean), FSFieldOffset(flag_links), XtRString, "False"}, {XtNcheckExistence, XtCBoolean, XtRBoolean, sizeof(Boolean), FSFieldOffset(check_existence), XtRString, "True"}, {XtNfileSelected, XtCBoolean, XtRBoolean, sizeof(Boolean), FSFieldOffset(file_selected), XtRString, "False"}, {XtNcurrentDirectory, XtCPathname, XtRString, sizeof(String), FSFieldOffset(current_directory), XtRString, NULL}, {XtNcurrentFile, XtCFilename, XtRString, sizeof(String), FSFieldOffset(current_file), XtRString, NULL}, {XtNtitle, XtCLabel, XtRString, sizeof(String), FSFieldOffset(title), XtRString, "File Selector"}, {XtNsortMode, XtCValue, XtRInt, sizeof(int), FSFieldOffset(sort_mode), XtRString, "2"}, {XtNpattern, XtCFile, XtRString, sizeof(String), FSFieldOffset(pattern), XtRString, NULL}, }; #undef FSFieldOffset #undef CoreFieldOffset /*---------------------------------------------------------------------------* C L A S S A L L O C A T I O N *---------------------------------------------------------------------------*/ XfwfFileSelectorClassRec xfwfFileSelectorClassRec = { { /* superclass */ (WidgetClass)SUPERCLASS, /* class_name */ "XfwfFileSelector", /* widget_size */ sizeof(XfwfFileSelectorRec), /* class_initialize */ NULL, /* class_part_initialize*/ NULL, /* class_inited */ FALSE, /* initialize */ (XtInitProc)Initialize, /* initialize_hook */ NULL, /* realize */ (XtRealizeProc)Realize, /* actions */ NULL, /* num_actions */ 0, /* resources */ resources, /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ (XtWidgetProc)Destroy, /* resize */ (XtWidgetProc)Resize, /* expose */ XtInheritExpose, /* set_values */ (XtSetValuesFunc)SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ NULL, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, /* Core Part */ { /* geometry_manager */ GeometryManager, /* change_managed */ XtInheritChangeManaged, /* insert_child */ XtInheritInsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ NULL }, /* Composite Part */ { /* no extra class data */ 0 } /* FileSelector Part */ }; WidgetClass xfwfFileSelectorWidgetClass = (WidgetClass)&xfwfFileSelectorClassRec; /*---------------------------------------------------------------------------* E X P O R T E D M E T H O D S *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Initialize() This procedure is called by the X toolkit to initialize the widget instance. The hook to this routine is in the initialize part of the core part of the class. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Initialize(request,new) Widget request,new; { int i; XfwfFileSelectorWidget fsw; char *str,*initial_file,path[MAXPATHLEN + 2]; static char *star = "*"; fsw = (XfwfFileSelectorWidget)new; FSHandCursor(fsw) = XCreateFontCursor(XtDisplay(fsw),XC_hand1); FSBusyCursor(fsw) = XCreateFontCursor(XtDisplay(fsw),XC_watch); for (i = 0; i < FS_NUM_CHILDREN; i++) FSNthWidget(fsw,i) = NULL; FSDirMgr(fsw) = NULL; FSPathList(fsw) = NULL; FSPathListCount(fsw) = 0; FSFileList(fsw) = NULL; FSFileListCount(fsw) = 0; str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char)); if (FSCurrentDirectory(fsw) != NULL) /* User Specified Path */ { strcpy(str,FSCurrentDirectory(fsw)); } else { getwd(path); strcpy(str,path); } FSCurrentDirectory(fsw) = str; str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char)); initial_file = FSCurrentFile(fsw); FSCurrentFile(fsw) = str; if (FSPattern(fsw) == NULL) FSPattern(fsw) = star; FSPattern(fsw) = StrCopy(FSPattern(fsw)); if (FSCorePart(request)->width <= 0) FSCorePart(new)->width = 500; if (FSCorePart(request)->height <= 0) FSCorePart(new)->height = 200; ChildrenCreate(fsw); GotoDeepestLegalDirectory(fsw); if (initial_file) SelectFileByName(fsw,initial_file); } /* End Initialize */ /*---------------------------------------------------------------------------* Realize() This function is called to realize a FileSelector widget. *---------------------------------------------------------------------------*/ static void Realize(gw,valueMask,attrs) Widget gw; XtValueMask *valueMask; XSetWindowAttributes *attrs; { XfwfFileSelectorWidget fsw; fsw = (XfwfFileSelectorWidget)gw; XtCreateWindow(gw,InputOutput,(Visual *)CopyFromParent, *valueMask,attrs); ChildrenRealize(fsw); ChildrenUpdate(fsw); Resize(gw); NotifySelectionChange(fsw); } /* End Realize */ /*---------------------------------------------------------------------------* Destroy() This function is called to destroy a fileSelector widget. *---------------------------------------------------------------------------*/ static void Destroy(fsw) XfwfFileSelectorWidget fsw; { XtFree(FSCurrentDirectory(fsw)); XtFree(FSCurrentFile(fsw)); } /* End Destroy */ /*---------------------------------------------------------------------------* Resize() This function is called to resize a fileSelector widget. *---------------------------------------------------------------------------*/ static void Resize(gw) Widget gw; { XfwfFileSelectorWidget w; w = (XfwfFileSelectorWidget)gw; ChildrenUpdate(w); } /* End Resize */ /*---------------------------------------------------------------------------* SetValues(gcurrent,grequest,gnew) This function is the external interface for setting resources. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static Boolean SetValues(gcurrent,grequest,gnew) Widget gcurrent,grequest,gnew; { XfwfFileSelectorWidget current,new; current = (XfwfFileSelectorWidget)gcurrent; new = (XfwfFileSelectorWidget)gnew; if (FSPattern(current) != FSPattern(new)) { XtWarning("Pattern Change Not Supported"); FSPattern(new) = FSPattern(current); } if (FSSortMode(current) != FSSortMode(new)) { XtWarning("Sort Mode Change Not Supported"); FSSortMode(new) = FSSortMode(current); } if (FSTitle(current) != FSTitle(new)) { XtWarning("Title Change Not Supported"); FSTitle(new) = FSTitle(current); } if (FSFileSelected(current) != FSFileSelected(new)) { XtWarning("Can't Change XtNfileSelected Resource"); FSFileSelected(new) = FSFileSelected(current); } if (FSCheckExistence(current) != FSCheckExistence(new)) { if (!FSCheckExistence(new)) { XtSetSensitive(FSNthWidget(new,FS_I_OK_BUTTON),True); } else { Chdir(new); } } if (FSShowOkButton(current) != FSShowOkButton(new)) { if (FSShowOkButton(new) == True) XtManageChild(FSNthWidget(new,FS_I_OK_BUTTON)); else XtUnmanageChild(FSNthWidget(new,FS_I_OK_BUTTON)); } if (FSShowCancelButton(current) != FSShowCancelButton(new)) { if (FSShowCancelButton(new) == True) XtManageChild(FSNthWidget(new,FS_I_CANCEL_BUTTON)); else XtUnmanageChild(FSNthWidget(new,FS_I_CANCEL_BUTTON)); } if (FSCurrentDirectory(current) != FSCurrentDirectory(new)) { strcpy(FSCurrentDirectory(current),FSCurrentDirectory(new)); FSCurrentDirectory(new) = FSCurrentDirectory(current); Chdir(new); } if (FSCurrentFile(current) != FSCurrentFile(new)) { char *new_name; new_name = FSCurrentFile(new); FSCurrentFile(new) = FSCurrentFile(current); SelectFileByName(new,new_name); } return(False); } /* End SetValues */ /*---------------------------------------------------------------------------* GeometryManager(w,request,reply) This routine acts as the geometry_manager method for the FileSelector widget. It is called when a child wants to resize/reposition itself. Currently, we allow all requests. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static XtGeometryResult GeometryManager(w,request,reply) Widget w; XtWidgetGeometry *request; XtWidgetGeometry *reply; { return(XtGeometryYes); } /* End GeometryManager */ /*---------------------------------------------------------------------------* L O C A L R O U T I N E S *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* ChildrenCreate(fsw) This routine creates the initial child widgets for the file selector widget and places them in the widget fsw. No placement or resizing is done. That is done by ChildrenUpdate(). *---------------------------------------------------------------------------*/ static void ChildrenCreate(fsw) XfwfFileSelectorWidget fsw; { Arg args[10]; static char *dummy_string_list[] = { NULL }; static char *text_box_translations = "#override\n<Key>Return: no-op()"; /* Title */ XtSetArg(args[0],XtNlabel,FSTitle(fsw)); XtSetArg(args[1],XtNborderWidth,0); FSNthWidget(fsw,FS_I_TITLE) = XtCreateManagedWidget("title", labelWidgetClass,(Widget)fsw,args,2); /* Current Directory Line */ XtSetArg(args[0],XtNtype,XawAsciiString); XtSetArg(args[1],XtNeditType,XawtextEdit); XtSetArg(args[2],XtNstring,""); XtSetArg(args[3],XtNautoFill,True); XtSetArg(args[4],XtNtranslations,text_box_translations); FSNthWidget(fsw,FS_I_CUR_DIR_TEXT) = XtCreateManagedWidget("cur_dir_text", asciiTextWidgetClass,(Widget)fsw,args,4); /* Current File Line */ XtSetArg(args[0],XtNtype,XawAsciiString); XtSetArg(args[1],XtNeditType,XawtextEdit); XtSetArg(args[2],XtNstring,""); XtSetArg(args[3],XtNautoFill,True); XtSetArg(args[4],XtNtranslations,text_box_translations); FSNthWidget(fsw,FS_I_CUR_FILE_TEXT) = XtCreateManagedWidget("cur_file_text", asciiTextWidgetClass,(Widget)fsw,args,4); /* Path From Root Title */ XtSetArg(args[0],XtNlabel,"Path From Root"); XtSetArg(args[1],XtNborderWidth,0); FSNthWidget(fsw,FS_I_PATH_LIST_TITLE) = XtCreateManagedWidget("path_list_title", labelWidgetClass,(Widget)fsw,args,2); /* Directory List */ XtSetArg(args[0],XtNlist,dummy_string_list); XtSetArg(args[1],XtNnumberStrings,0); FSNthWidget(fsw,FS_I_PATH_LIST) = XtCreateManagedWidget("path_list", xfwfScrolledListWidgetClass,(Widget)fsw,args,2); XtAddCallback(FSNthWidget(fsw,FS_I_PATH_LIST), XtNcallback,(XtCallbackProc)ClickOnPathList,fsw); /* File List Title */ XtSetArg(args[0],XtNlabel,"Directory Contents"); XtSetArg(args[1],XtNborderWidth,0); FSNthWidget(fsw,FS_I_FILE_LIST_TITLE) = XtCreateManagedWidget("file_list_title", labelWidgetClass,(Widget)fsw,args,2); /* File List */ XtSetArg(args[0],XtNlist,dummy_string_list); XtSetArg(args[1],XtNnumberStrings,0); FSNthWidget(fsw,FS_I_FILE_LIST) = XtCreateManagedWidget("file_list", xfwfScrolledListWidgetClass,(Widget)fsw,args,2); XtAddCallback(FSNthWidget(fsw,FS_I_FILE_LIST), XtNcallback,(XtCallbackProc)ClickOnFileList,fsw); /* Goto Button */ XtSetArg(args[0],XtNlabel,"Goto"); /* XtSetArg(args[1],XtNborderWidth,2); */ FSNthWidget(fsw,FS_I_GOTO_BUTTON) = XtCreateManagedWidget("goto_button", commandWidgetClass,(Widget)fsw,args,1); XtAddCallback(FSNthWidget(fsw,FS_I_GOTO_BUTTON), XtNcallback,(XtCallbackProc)ButtonGoto,fsw); /* Select Button */ XtSetArg(args[0],XtNlabel,"Select"); /* XtSetArg(args[1],XtNborderWidth,2); */ FSNthWidget(fsw,FS_I_SELECT_BUTTON) = XtCreateManagedWidget("select_button", commandWidgetClass,(Widget)fsw,args,1); XtAddCallback(FSNthWidget(fsw,FS_I_SELECT_BUTTON), XtNcallback,(XtCallbackProc)ButtonSelect,fsw); /* Up Button */ XtSetArg(args[0],XtNlabel,"Up"); /* XtSetArg(args[1],XtNborderWidth,2); */ FSNthWidget(fsw,FS_I_UP_BUTTON) = XtCreateManagedWidget("up_button", commandWidgetClass,(Widget)fsw,args,1); XtAddCallback(FSNthWidget(fsw,FS_I_UP_BUTTON), XtNcallback,(XtCallbackProc)ButtonUp,fsw); /* OK Button */ XtSetArg(args[0],XtNlabel,"OK"); /* XtSetArg(args[1],XtNborderWidth,2); */ FSNthWidget(fsw,FS_I_OK_BUTTON) = XtCreateManagedWidget("ok_button", commandWidgetClass,(Widget)fsw,args,1); XtAddCallback(FSNthWidget(fsw,FS_I_OK_BUTTON), XtNcallback,(XtCallbackProc)ButtonOk,fsw); /* Cancel Button */ XtSetArg(args[0],XtNlabel,"Cancel"); /* XtSetArg(args[1],XtNborderWidth,2); */ FSNthWidget(fsw,FS_I_CANCEL_BUTTON) = XtCreateManagedWidget("cancel_button", commandWidgetClass,(Widget)fsw,args,1); XtAddCallback(FSNthWidget(fsw,FS_I_CANCEL_BUTTON), XtNcallback,(XtCallbackProc)ButtonCancel,fsw); } /* End ChildrenCreate */ /*---------------------------------------------------------------------------* ChildrenRealize(fsw) This routine realizes the child widgets. The widgets must already have been created and initialized. Their coordinates should already have been set. *---------------------------------------------------------------------------*/ static void ChildrenRealize(fsw) XfwfFileSelectorWidget fsw; { int i; Widget widget; for (i = 0; i < FS_NUM_CHILDREN; i++) { if (FSNthWidget(fsw,i) != NULL) { widget = FSNthWidget(fsw,i); XtRealizeWidget(widget); if ((i == FS_I_OK_BUTTON && !FSShowOkButton(fsw)) || (i == FS_I_CANCEL_BUTTON && !FSShowCancelButton(fsw))) { XtUnmanageChild(widget); } } } } /* End ChildrenRealize */ /*---------------------------------------------------------------------------* ChildrenRecalculate(fsw) This routine takes a file selector widget and recalculates the coordinates and sizes of the constituent components based on the current size of the file selector. This function does not actually change the child widgets, it just calculates the coordinates and caches the coordinates in the FileSelector widget. *---------------------------------------------------------------------------*/ static void ChildrenRecalculate(fsw) XfwfFileSelectorWidget fsw; { BOX *coords; Widget widget; int i,w,h,empty_space,gap,orig_path_list_h,orig_file_list_h,top; XtWidgetGeometry parent_idea,child_idea; w = FSCorePart(fsw)->width; h = FSCorePart(fsw)->height; /* Get The Child Widgets Current Widths And Heights */ for (i = 0; i < FS_NUM_CHILDREN; i++) { if (FSNthWidget(fsw,i) != NULL) { widget = FSNthWidget(fsw,i); coords = FSNthCoords(fsw,i); BoxW(coords) = CoreWidth(widget); BoxH(coords) = CoreHeight(widget); } } /* Adjust Widths */ BoxW(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) = .7 * w; BoxW(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) = .7 * w; BoxW(FSNthCoords(fsw,FS_I_GOTO_BUTTON)) = .15 * w; BoxW(FSNthCoords(fsw,FS_I_SELECT_BUTTON)) = .15 * w; BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)) = .45 * w; BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)) = .45 * w; BoxW(FSNthCoords(fsw,FS_I_UP_BUTTON)) = BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)) * .35; BoxW(FSNthCoords(fsw,FS_I_OK_BUTTON)) = BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)) * .35; BoxW(FSNthCoords(fsw,FS_I_CANCEL_BUTTON)) = BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)) * .35; /* Adjust Heights */ BoxH(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) = max(BoxH(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)), BoxH(FSNthCoords(fsw,FS_I_GOTO_BUTTON))); BoxH(FSNthCoords(fsw,FS_I_GOTO_BUTTON)) = BoxH(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)); BoxH(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) = max(BoxH(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)), BoxH(FSNthCoords(fsw,FS_I_SELECT_BUTTON))); BoxH(FSNthCoords(fsw,FS_I_SELECT_BUTTON)) = BoxH(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)); empty_space = h - (BoxH(FSNthCoords(fsw,FS_I_TITLE)) + BoxH(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) + BoxH(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) + BoxH(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE)) + BoxH(FSNthCoords(fsw,FS_I_OK_BUTTON))); gap = .025 * h; BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)) = empty_space - 8 * gap; BoxH(FSNthCoords(fsw,FS_I_FILE_LIST)) = empty_space - 8 * gap; orig_path_list_h = BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)); orig_file_list_h = BoxH(FSNthCoords(fsw,FS_I_FILE_LIST)); /* Listen To Child Height Requests For Lists */ parent_idea.request_mode = CWWidth | CWHeight; parent_idea.width = BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)); parent_idea.height = BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)); XtQueryGeometry(FSNthWidget(fsw,FS_I_PATH_LIST), &parent_idea,&child_idea); if ((child_idea.request_mode & CWHeight) && (child_idea.height < parent_idea.height)) { BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)) = child_idea.height; } parent_idea.request_mode = CWWidth | CWHeight; parent_idea.width = BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)); parent_idea.height = BoxH(FSNthCoords(fsw,FS_I_FILE_LIST)); XtQueryGeometry(FSNthWidget(fsw,FS_I_FILE_LIST), &parent_idea,&child_idea); if ((child_idea.request_mode & CWHeight) && (child_idea.height < parent_idea.height)) { BoxH(FSNthCoords(fsw,FS_I_FILE_LIST)) = child_idea.height; } /* Make Sure Both Lists Have Same Minimum Height */ BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)) = min(BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)), BoxH(FSNthCoords(fsw,FS_I_FILE_LIST))); BoxH(FSNthCoords(fsw,FS_I_FILE_LIST)) = min(BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)), BoxH(FSNthCoords(fsw,FS_I_FILE_LIST))); /* Vertical Positions */ BoxY(FSNthCoords(fsw,FS_I_TITLE)) = gap; BoxY(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) = (BoxY(FSNthCoords(fsw,FS_I_TITLE)) + BoxH(FSNthCoords(fsw,FS_I_TITLE))) + gap; BoxY(FSNthCoords(fsw,FS_I_GOTO_BUTTON)) = BoxY(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)); BoxY(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) = (BoxY(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) + BoxH(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT))) + gap; BoxY(FSNthCoords(fsw,FS_I_SELECT_BUTTON)) = BoxY(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)); BoxY(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE)) = (BoxY(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) + BoxH(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT))) + gap; BoxY(FSNthCoords(fsw,FS_I_FILE_LIST_TITLE)) = BoxY(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE)); BoxY(FSNthCoords(fsw,FS_I_PATH_LIST)) = (BoxY(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE)) + BoxH(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE))) + gap + (orig_path_list_h - BoxH(FSNthCoords(fsw,FS_I_PATH_LIST))) / 2; BoxY(FSNthCoords(fsw,FS_I_FILE_LIST)) = BoxY(FSNthCoords(fsw,FS_I_PATH_LIST)); top = BoxY(FSNthCoords(fsw,FS_I_PATH_LIST)) + BoxH(FSNthCoords(fsw,FS_I_PATH_LIST)); empty_space = h - top; BoxY(FSNthCoords(fsw,FS_I_UP_BUTTON)) = top + (h - top - BoxH(FSNthCoords(fsw,FS_I_UP_BUTTON))) / 2; BoxY(FSNthCoords(fsw,FS_I_OK_BUTTON)) = top + (h - top - BoxH(FSNthCoords(fsw,FS_I_OK_BUTTON))) / 2; BoxY(FSNthCoords(fsw,FS_I_CANCEL_BUTTON)) = top + (h - top - BoxH(FSNthCoords(fsw,FS_I_CANCEL_BUTTON))) / 2; /* Horizontal Positions */ BoxX(FSNthCoords(fsw,FS_I_TITLE)) = (w - BoxW(FSNthCoords(fsw,FS_I_TITLE))) / 2; empty_space = w - (BoxW(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) + BoxW(FSNthCoords(fsw,FS_I_GOTO_BUTTON))); gap = empty_space / 3; BoxX(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) = gap; BoxX(FSNthCoords(fsw,FS_I_GOTO_BUTTON)) = (BoxX(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT)) + BoxW(FSNthCoords(fsw,FS_I_CUR_DIR_TEXT))) + gap; empty_space = w - (BoxW(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) + BoxW(FSNthCoords(fsw,FS_I_SELECT_BUTTON))); gap = empty_space / 3; BoxX(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) = gap; BoxX(FSNthCoords(fsw,FS_I_SELECT_BUTTON)) = (BoxX(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT)) + BoxW(FSNthCoords(fsw,FS_I_CUR_FILE_TEXT))) + gap; empty_space = w - (BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)) + BoxW(FSNthCoords(fsw,FS_I_FILE_LIST))); gap = empty_space / 3; BoxX(FSNthCoords(fsw,FS_I_PATH_LIST)) = gap; BoxX(FSNthCoords(fsw,FS_I_FILE_LIST)) = (BoxX(FSNthCoords(fsw,FS_I_PATH_LIST)) + BoxW(FSNthCoords(fsw,FS_I_PATH_LIST))) + gap; BoxX(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE)) = (BoxX(FSNthCoords(fsw,FS_I_PATH_LIST)) + (BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)) - BoxW(FSNthCoords(fsw,FS_I_PATH_LIST_TITLE))) / 2); BoxX(FSNthCoords(fsw,FS_I_FILE_LIST_TITLE)) = (BoxX(FSNthCoords(fsw,FS_I_FILE_LIST)) + (BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)) - BoxW(FSNthCoords(fsw,FS_I_FILE_LIST_TITLE))) / 2); empty_space = BoxW(FSNthCoords(fsw,FS_I_PATH_LIST)) - BoxW(FSNthCoords(fsw,FS_I_UP_BUTTON)); gap = empty_space / 2; BoxX(FSNthCoords(fsw,FS_I_UP_BUTTON)) = BoxX(FSNthCoords(fsw,FS_I_PATH_LIST)) + gap; empty_space = BoxW(FSNthCoords(fsw,FS_I_FILE_LIST)) - (BoxW(FSNthCoords(fsw,FS_I_OK_BUTTON)) + BoxW(FSNthCoords(fsw,FS_I_CANCEL_BUTTON))); gap = empty_space / 3; BoxX(FSNthCoords(fsw,FS_I_OK_BUTTON)) = BoxX(FSNthCoords(fsw,FS_I_FILE_LIST)) + gap; BoxX(FSNthCoords(fsw,FS_I_CANCEL_BUTTON)) = (BoxX(FSNthCoords(fsw,FS_I_OK_BUTTON)) + BoxW(FSNthCoords(fsw,FS_I_OK_BUTTON))) + gap; } /* End ChildrenRecalculate */ /*---------------------------------------------------------------------------* ChildrenUpdate(fsw) This routine takes a File Selector widget <fsw> and updates the child widgets by recalculating their coordinates and setting the appropriate resources. *---------------------------------------------------------------------------*/ static void ChildrenUpdate(fsw) XfwfFileSelectorWidget fsw; { int i; Widget widget; BOX *coords; Boolean not_at_root; XfwfScrolledListWidget file_list; ChildrenRecalculate(fsw); for (i = 0; i < FS_NUM_CHILDREN; i++) { if (FSNthWidget(fsw,i) != NULL) { widget = FSNthWidget(fsw,i); coords = FSNthCoords(fsw,i); XtMoveWidget(widget,BoxX(coords),BoxY(coords)); XtResizeWidget(widget,BoxW(coords),BoxH(coords), CoreBorderWidth(widget)); } } file_list = (XfwfScrolledListWidget) FSNthWidget(fsw,FS_I_FILE_LIST); if (FSPathListCount(fsw) != 1) not_at_root = True; else not_at_root = False; XtSetSensitive(FSNthWidget(fsw,FS_I_UP_BUTTON),not_at_root); } /* End ChildrenUpdate */ /*---------------------------------------------------------------------------* I N T E R N A L C A L L B A C K S *---------------------------------------------------------------------------*/ static void ButtonUp(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { strcat(FSCurrentDirectory(fsw),".."); Chdir(fsw); } /* End ButtonUp */ static void ButtonOk(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { XfwfFileSelectorOkButtonReturnStruct ret; ret.path = FSCurrentDirectory(fsw); ret.file = FSCurrentFile(fsw); ret.file_box_text = GetFileBoxText(fsw); XtCallCallbacks((Widget)fsw,XtNokButtonCallback,(XtPointer)&ret); } /* End ButtonOk */ static void ButtonCancel(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { XtCallCallbacks((Widget)fsw,XtNcancelButtonCallback,NULL); } /* End ButtonCancel */ static void ButtonGoto(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { Widget cur_dir_text; Arg args[10]; String path; XtSetArg(args[0],XtNstring,(XtArgVal)(&path)); cur_dir_text = FSNthWidget(fsw,FS_I_CUR_DIR_TEXT); XtGetValues(cur_dir_text,args,1); strcpy(FSCurrentDirectory(fsw),path); Chdir(fsw); } /* End ButtonGoto */ static void ButtonSelect(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { String file; file = GetFileBoxText(fsw); if (SelectFileByName(fsw,file) == False) XBell(XtDisplay(fsw),0); UpdateTextLines(fsw); } /* End ButtonSelect */ static char *GetFileBoxText(fsw) XfwfFileSelectorWidget fsw; { char *text; Arg args[1]; Widget file_box_widget; XtSetArg(args[0],XtNstring,(XtArgVal)(&text)); file_box_widget = FSNthWidget(fsw,FS_I_CUR_FILE_TEXT); XtGetValues(file_box_widget,args,1); return(text); } /* End GetFileBoxText */ static void ClickOnPathList(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { int i; XfwfScrolledListReturnStruct *ret; ret = (XfwfScrolledListReturnStruct *)call_data; if (ret->index == -1) { UnselectAll(fsw); /* Click On Blank Space */ return; } strcpy(FSCurrentDirectory(fsw),"/"); for (i = 1; i <= ret->index; i++) { strcat(FSCurrentDirectory(fsw),FSPathList(fsw)[i]); strcat(FSCurrentDirectory(fsw),"/"); } Chdir(fsw); } /* End ClickOnPathList */ static void ClickOnFileList(w,fsw,call_data) Widget w; XfwfFileSelectorWidget fsw; XtPointer call_data; { XfwfScrolledListReturnStruct *ret; ret = (XfwfScrolledListReturnStruct *)call_data; if (ret->index == -1) UnselectAll(fsw); /* Click On Blank Space */ else SelectFileByIndex(fsw,ret->index); } /* End ClickOnFileList */ /*---------------------------------------------------------------------------* I N T E R N A L S U P P O R T R O U T I N E S *---------------------------------------------------------------------------*/ static void SelectFileByIndex(fsw,index) XfwfFileSelectorWidget fsw; int index; { DirEntry *dir_entry; DirectoryMgrGotoItem(FSDirMgr(fsw),index); dir_entry = DirectoryMgrCurrentEntry(FSDirMgr(fsw)); if (dir_entry == NULL) { fprintf(stderr,"SelectFileByIndex: Entry %d invalid\n",index); exit(-1); } if (DirEntryIsDir(dir_entry) || DirEntryIsDirectoryLink(dir_entry)) { strcat(FSCurrentDirectory(fsw),DirEntryFileName(dir_entry)); Chdir(fsw); } else if (!DirEntryIsBrokenLink(dir_entry)) /* File */ { strcpy(FSCurrentFile(fsw),DirEntryFileName(dir_entry)); if (FSCheckExistence(fsw)) { XtSetSensitive(FSNthWidget(fsw,FS_I_OK_BUTTON),True); } FSFileSelected(fsw) = True; TextWidgetSetText(FSNthWidget(fsw,FS_I_CUR_FILE_TEXT), FSCurrentFile(fsw)); XfwfScrolledListHighlightItem(FSNthWidget(fsw,FS_I_FILE_LIST), index); NotifySelectionChange(fsw); } else /* Broken Link */ { XBell(XtDisplay(fsw),0); UnselectAll(fsw); } } /* End SelectFileByIndex */ static Boolean SelectFileByName(fsw,name) XfwfFileSelectorWidget fsw; char *name; { if (DirectoryMgrGotoNamedItem(FSDirMgr(fsw),name) == FALSE) { return(False); } SelectFileByIndex(fsw,DirectoryMgrCurrentIndex(FSDirMgr(fsw))); return(True); } /* End SelectFileByName */ static void UnselectAll(fsw) XfwfFileSelectorWidget fsw; { Boolean old_file_selected_flag; old_file_selected_flag = FSFileSelected(fsw); if (FSCheckExistence(fsw)) { XtSetSensitive(FSNthWidget(fsw,FS_I_OK_BUTTON),False); } FSCurrentFile(fsw)[0] = '\0'; FSFileSelected(fsw) = False; TextWidgetSetText(FSNthWidget(fsw,FS_I_CUR_FILE_TEXT), FSCurrentFile(fsw)); XfwfScrolledListUnhighlightAll(FSNthWidget(fsw,FS_I_FILE_LIST)); if (old_file_selected_flag) NotifySelectionChange(fsw); } /* End UnselectAll */ static void NotifySelectionChange(fsw) XfwfFileSelectorWidget fsw; { XfwfFileSelectorSelectionChangeReturnStruct ret; if (FSFileSelected(fsw) == True) { ret.file_selected = True; ret.path = FSCurrentDirectory(fsw); ret.file = FSCurrentFile(fsw); } else { ret.file_selected = False; ret.path = NULL; ret.file = NULL; } XtCallCallbacks((Widget)fsw,XtNselectionChangeCallback, (XtPointer)&ret); } /* End NotifySelectionChange */ /*---------------------------------------------------------------------------* GotoDeepestLegalDirectory(fsw) This function takes a FileSelector widget <fsw> and modifies the directory string in FSCurrentDirectory(fsw) to be the deepest legal directory above the string. Partial or incorrect directory names are stripped starting at the end. This routine takes a File Selector widget <fsw> and updates the child widgets by recalculating their coordinates and setting the appropriate resources. The old directory manager is closed and a new one is opened for this directory. The file and path lists are deallocated, reallocated, and loaded with the path and file data lists. The lists are then reset in the scrolled list widgets. This routine requires that all the child widgets have already been created. *---------------------------------------------------------------------------*/ static void GotoDeepestLegalDirectory(fsw) XfwfFileSelectorWidget fsw; { char *dir,*end_of_dir; char temp[MAXPATHLEN + 2]; dir = FSCurrentDirectory(fsw); for (end_of_dir = dir; *end_of_dir != '\0'; ++ end_of_dir); while (1) { if (DirectoryPathExpand(dir,temp) == NULL) { XBell(XtDisplay(fsw), 0); while (*end_of_dir != '/' && end_of_dir != dir) { -- end_of_dir; } *end_of_dir = '\0'; } else { strcpy(FSCurrentDirectory(fsw),temp); break; } } UnselectAll(fsw); UpdateLists(fsw); } /* End GotoDeepestLegalDirectory */ /*---------------------------------------------------------------------------* UpdateLists(fsw) This routine takes a FileSelector widget and builds new path and file lists from the current directory, sort mode, and pattern strings. The lists and text items are then changed. *---------------------------------------------------------------------------*/ static void UpdateLists(fsw) XfwfFileSelectorWidget fsw; { int i,count; char *dir,*start; DirEntry *dir_entry; DirectoryMgr *dir_mgr; char temp[MAXPATHLEN + 2]; if (FSDirMgr(fsw)) DirectoryMgrClose(FSDirMgr(fsw)); dir_mgr = DirectoryMgrSimpleOpen(FSCurrentDirectory(fsw), FSSortMode(fsw), FSPattern(fsw)); FSDirMgr(fsw) = dir_mgr; if (FSPathList(fsw) != NULL) { for (i = 0; i < FSPathListCount(fsw); i++) free(FSPathList(fsw)[i]); free(FSPathList(fsw)); } if (FSFileList(fsw) != NULL) { for (i = 0; i < FSFileListCount(fsw); i++) free(FSFileList(fsw)[i]); free(FSFileList(fsw)); } FSFileListCount(fsw) = DirectoryMgrFilteredCount(FSDirMgr(fsw)); FSPathListCount(fsw) = 1; for (dir = FSCurrentDirectory(fsw) + 1; *dir != '\0'; dir++) { if (*dir == '/') ++ FSPathListCount(fsw); } FSFileList(fsw) = (char **)malloc(sizeof(char *) * (FSFileListCount(fsw) + 1)); if (FSFileList(fsw) == NULL) { fprintf(stderr,"UpdateLists: Out Of Memory\n"); exit(-1); } for (i = 0; i < FSFileListCount(fsw); i++) { dir_entry = DirectoryMgrNextEntry(FSDirMgr(fsw)); if (dir_entry == NULL) XtError("Inconsistent Directory"); strcpy(temp,DirEntryFileName(dir_entry)); if (DirEntryIsDir(dir_entry)) strcat(temp,"/"); else if (DirEntryIsBrokenLink(dir_entry)) strcat(temp," X"); else if (DirEntryIsDirectoryLink(dir_entry)) strcat(temp,"/"); else if (DirEntryIsSymLink(dir_entry) && FSFlagLinks(fsw)) strcat(temp," @"); FSFileList(fsw)[i] = StrCopy(temp); } FSFileList(fsw)[i] = NULL; FSPathList(fsw) = (char **)malloc(sizeof(char *) * (FSPathListCount(fsw) + 1)); start = FSCurrentDirectory(fsw); FSPathList(fsw)[0] = StrCopy("/"); for (i = 1; i < FSPathListCount(fsw); i++) { while (*start != '\0' && *start == '/') ++start; count = 0; while (*start != '\0' && *start != '/') temp[count++] = *start++; temp[count++] = '\0'; FSPathList(fsw)[i] = StrCopy(temp); } FSPathList(fsw)[i] = NULL; XfwfScrolledListSetList(FSNthWidget(fsw,FS_I_PATH_LIST), FSPathList(fsw),FSPathListCount(fsw),True,NULL); XfwfScrolledListSetList(FSNthWidget(fsw,FS_I_FILE_LIST), FSFileList(fsw),FSFileListCount(fsw),True,NULL); UpdateTextLines(fsw); } /* End UpdateLists */ static void UpdateTextLines(fsw) XfwfFileSelectorWidget fsw; { TextWidgetSetText(FSNthWidget(fsw,FS_I_CUR_DIR_TEXT), FSCurrentDirectory(fsw)); TextWidgetSetText(FSNthWidget(fsw,FS_I_CUR_FILE_TEXT), FSCurrentFile(fsw)); } /* End UpdateTextLines */ static void Chdir(fsw) XfwfFileSelectorWidget fsw; { DoBusyCursor((Widget)fsw); GotoDeepestLegalDirectory(fsw); ChildrenUpdate(fsw); UndoBusyCursor((Widget)fsw); } /* End Chdir */ static void DoBusyCursor(w) Widget w; { #ifndef NO_BUSY_GRAB if (XtIsRealized(w)) { XGrabPointer(XtDisplay(w),XtWindow(w),True,None, GrabModeSync,GrabModeSync,None,FSBusyCursor(w), CurrentTime); } #endif } /* End DoBusyCursor */ static void UndoBusyCursor(w) Widget w; { #ifndef NO_BUSY_GRAB if (XtIsRealized(w)) { XUngrabPointer(XtDisplay(w),CurrentTime); } #endif } /* End UndoBusyCursor */ static void TextWidgetSetText(tw,text) Widget tw; char *text; { Arg args[3]; int length,insert_position; #ifdef X11R3 static char text_widget_storage[MAXPATHLEN + 2]; #endif length = strlen(text); insert_position = max(length,0); #ifdef X11R3 /* XtTextSetInsertionPoint(tw,insert_position); XtSetArg(args[0],XtNstring,text); XtSetValues(tw,args,1); { XtTextBlock block; block.firstPos = 0; block.length = length + 1; block.ptr = text; block.format = FMT8BIT; XtTextReplace(fsw,0,block.length - 1,&block); } */ #else XtSetArg(args[0],XtNstring,text); XtSetValues(tw,args,1); XawTextSetInsertionPoint(tw,insert_position); #endif } /* End TextWidgetSetText */ /*---------------------------------------------------------------------------* E X T E R N A L R O U T I N E S *---------------------------------------------------------------------------*/ void XfwfFileSelectorChangeDirectory(fsw,dir) XfwfFileSelectorWidget fsw; char *dir; { strcpy(FSCurrentDirectory(fsw),dir); Chdir(fsw); } /* End XfwfFileSelectorChangeDirectory */ void XfwfFileSelectorRefresh(fsw) XfwfFileSelectorWidget fsw; { XfwfFileSelectorChangeDirectory(fsw,"."); } /* End XfwfFileSelectorRefresh */ void XfwfFileSelectorGetStatus(fsw,ssp) XfwfFileSelectorWidget fsw; XfwfFileSelectorStatusStruct *ssp; { ssp->file_selected = FSFileSelected(fsw); ssp->path = FSCurrentDirectory(fsw); ssp->file = FSCurrentFile(fsw); ssp->file_box_text = GetFileBoxText(fsw); } /* End XfwfFileSelectorGetStatus */ SHAR_EOF fi if test -f 'FileSel.h' then echo shar: "will not over-write existing file 'FileSel.h'" else cat << \SHAR_EOF > 'FileSel.h' /***************************************************************************** FileSelector.h This file contains the user includes for the FileSelector widget. ******************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _FILESELECTOR_H_ #define _FILESELECTOR_H_ #include "ScrList.h" #include "DirMgr.h" extern WidgetClass xfwfFileSelectorWidgetClass; typedef struct _XfwfFileSelectorClassRec *XfwfFileSelectorWidgetClass; typedef struct _XfwfFileSelectorRec *XfwfFileSelectorWidget; #define XtNpathname XtNcurrentDirectory /* For Compatibility */ #ifndef XtNtitle #define XtNtitle "title" #endif #define XtNcurrentDirectory "currentDirectory" #define XtNcurrentFile "currentFile" #define XtNsortMode "sortMode" #define XtNpattern "pattern" #define XtNokButtonCallback "okButtonCallback" #define XtNcancelButtonCallback "cancelButtonCallback" #define XtNselectionChangeCallback "selectionChangeCallback" #define XtNshowOkButton "showOkButton" #define XtNshowCancelButton "showCancelButton" #define XtNfileSelected "fileSelected" #define XtNflagLinks "flagLinks" #define XtNcheckExistence "checkExistence" #define XtCPathname "Pathname" #define XtCFilename "Filename" typedef struct _XfwfFileSelectorOkButtonReturnStruct { char *path; char *file; char *file_box_text; } XfwfFileSelectorOkButtonReturnStruct; typedef struct _XfwfFileSelectorSelectionChangeReturnStruct { Boolean file_selected; char *path; char *file; } XfwfFileSelectorSelectionChangeReturnStruct; typedef struct _XfwfFileSelectorStatusStruct { Boolean file_selected; char *path; char *file; char *file_box_text; } XfwfFileSelectorStatusStruct; /*---------------------------------------------------------------------------* E X T E R N A L F U N C T I O N S *---------------------------------------------------------------------------*/ #if (!NeedFunctionPrototypes) void XfwfFileSelectorChangeDirectory(); void XfwfFileSelectorRefresh(); void XfwfFileSelectorGetStatus(); #else void XfwfFileSelectorChangeDirectory(XfwfFileSelectorWidget fsw, char *dir); void XfwfFileSelectorRefresh(XfwfFileSelectorWidget fsw); void XfwfFileSelectorGetStatus(XfwfFileSelectorWidget fsw, XfwfFileSelectorStatusStruct *ssp); #endif #endif SHAR_EOF fi if test -f 'FileSelP.h' then echo shar: "will not over-write existing file 'FileSelP.h'" else cat << \SHAR_EOF > 'FileSelP.h' /**************************************************************************** FileSelectorP.h This file is the private definition file for the File Selector Widget. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _FILESELECTORP_H_ #define _FILESELECTORP_H_ #include "DirMgr.h" #include <X11/Xaw/Cardinals.h> #include <X11/CoreP.h> #include <X11/Core.h> /*---------------------------------------------------------------------------* C O N S T A N T S *---------------------------------------------------------------------------*/ #define FS_DIR_STRING_SIZE 512 /* The following indices are used to find the appropriate widget data from the arrays that the data items are stored in. */ #define FS_I_TITLE 0 /* Title Index */ #define FS_I_CUR_DIR_TEXT 1 /* Current Directory Label Index */ #define FS_I_PATH_LIST_TITLE 2 /* Path From Root List Title Index */ #define FS_I_FILE_LIST_TITLE 3 /* File List Title Index */ #define FS_I_PATH_LIST 4 /* Path From Root List Index */ #define FS_I_FILE_LIST 5 /* File List Index */ #define FS_I_OK_BUTTON 6 /* OK Button Index */ #define FS_I_CANCEL_BUTTON 7 /* Cancel Button Index */ #define FS_I_UP_BUTTON 8 /* Go Up Directory Button */ #define FS_I_GOTO_BUTTON 9 /* Go To Directory Button */ #define FS_I_CUR_FILE_TEXT 10 /* Filename Text Line */ #define FS_I_SELECT_BUTTON 11 /* Select Filename Button */ #define FS_NUM_CHILDREN 12 /* Count Of Above Indices */ /*---------------------------------------------------------------------------* S T R U C T U R E & W I D G E T A C C E S S M A C R O S *---------------------------------------------------------------------------*/ #define BoxX(b) ((b)->x) #define BoxY(b) ((b)->y) #define BoxW(b) ((b)->w) #define BoxH(b) ((b)->h) #define ChildInfoCoords(ci) (&((ci)->coords)) #define ChildInfoWidget(ci) ((ci)->widget) #define FSCorePart(w) (&((w)->core)) #define FSCompositePart(w) (&((w)->composite)) #define FSMyPart(w) (&((w)->fileSelector)) #define FSDirMgr(w) (FSMyPart(w)->dir_mgr) #define FSChildren(w) (FSMyPart(w)->children) #define FSCurrentDirectory(w) (FSMyPart(w)->current_directory) #define FSCurrentFile(w) (FSMyPart(w)->current_file) #define FSTitle(w) (FSMyPart(w)->title) #define FSPathList(w) (FSMyPart(w)->path_list) #define FSFileList(w) (FSMyPart(w)->file_list) #define FSSortMode(w) (FSMyPart(w)->sort_mode) #define FSPattern(w) (FSMyPart(w)->pattern) #define FSPathListCount(w) (FSMyPart(w)->path_list_count) #define FSFileListCount(w) (FSMyPart(w)->file_list_count) #define FSOkCallbacks(w) (FSMyPart(w)->ok_button_callbacks) #define FSCancelCallbacks(w) (FSMyPart(w)->cancel_button_callbacks) #define FSSelChangeCallbacks(w) (FSMyPart(w)->sel_change_callbacks) #define FSShowOkButton(w) (FSMyPart(w)->show_ok_button) #define FSShowCancelButton(w) (FSMyPart(w)->show_cancel_button) #define FSFileSelected(w) (FSMyPart(w)->file_selected) #define FSBusyCursor(w) (FSMyPart(w)->busy_cursor) #define FSHandCursor(w) (FSMyPart(w)->hand_cursor) #define FSFlagLinks(w) (FSMyPart(w)->flag_links) #define FSCheckExistence(w) (FSMyPart(w)->check_existence) #define FSNthChildInfo(w,n) (&(FSChildren(w)[n])) #define FSNthCoords(w,n) (ChildInfoCoords(FSNthChildInfo(w,n))) #define FSNthWidget(w,n) (ChildInfoWidget(FSNthChildInfo(w,n))) #define CoreWidth(w) ((w)->core.width) #define CoreHeight(w) ((w)->core.height) #define CoreBorderWidth(w) ((w)->core.border_width) /*---------------------------------------------------------------------------* T Y P E D E F I N I T I O N S *---------------------------------------------------------------------------*/ typedef struct { int x; int y; int w; int h; } BOX; /*---------------------------------------------------------------------------* W I D G E T S T R U C T U R E D E F I N I T I O N *---------------------------------------------------------------------------*/ typedef struct { BOX coords; Widget widget; } XfwfFileSelectorChildInfo; typedef struct { XtCallbackList ok_button_callbacks; XtCallbackList cancel_button_callbacks; XtCallbackList sel_change_callbacks; Boolean show_ok_button; Boolean show_cancel_button; Boolean file_selected; Boolean flag_links; Boolean check_existence; char *title; int sort_mode; char *pattern; DIRECTORY_MGR *dir_mgr; XfwfFileSelectorChildInfo children[FS_NUM_CHILDREN]; char *current_directory; char *current_file; char **path_list; char **file_list; int path_list_count; int file_list_count; Cursor busy_cursor; Cursor hand_cursor; } XfwfFileSelectorPart; typedef struct _XfwfFileSelectorClassPart { int empty; } XfwfFileSelectorClassPart; typedef struct _XfwfFileSelectorClassRec { CoreClassPart core_class; CompositeClassPart composite_class; XfwfFileSelectorClassPart fileSelector_class; } XfwfFileSelectorClassRec; /* This Is What A Widget Instance Points To */ typedef struct _XfwfFileSelectorRec { CorePart core; CompositePart composite; XfwfFileSelectorPart fileSelector; } XfwfFileSelectorRec; extern XfwfFileSelectorClassRec xfwfFileSelectorClassRec; #endif SHAR_EOF fi if test -f 'Makefile.1' then echo shar: "will not over-write existing file 'Makefile.1'" else cat << \SHAR_EOF > 'Makefile.1' CFLAGS= -g -I/usr/local/X11R4/include -I/usr/local/X11R4/include -DXMGT_HFS SRCS = help.c build.c comment.c doit.c edit.c \ mgt.c parse.c play.c tree.c Board.c x11.4.c xutil.c \ advunix.c goserver.c DirMgr.c Directory.c \ FileSel.c MultiList.c RegExp.c ScrList.c OBJS = help.o build.o comment.o doit.o edit.o \ mgt.o parse.o play.o tree.o Board.o x11.4.o xutil.o \ advunix.o goserver.o DirMgr.o Directory.o \ FileSel.o MultiList.o RegExp.o ScrList.o xmgt: $(OBJS) rm -f xmgt cc -o xmgt $(OBJS) -lXaw -lXmu -lXt -lXext -lX11 -lm SHAR_EOF fi if test -f 'MultiList.c' then echo shar: "will not over-write existing file 'MultiList.c'" else cat << \SHAR_EOF > 'MultiList.c' /**************************************************************************** MultiList.c This file contains the implementation of the Picasso List widget. Its functionality is intended to be similar to The Athena List widget, with some extra features added. This code is loosely based on the Athena List source which is why the MIT copyright notice appears below. The code was changed substantially in V3.4 to change the action/callback interface which was unnecessarily ugly. Code using some features of the old interface may need to be changed. Hope the changes don't make people's lives too miserable. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ /* * Copyright 1989 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Original Athena Author: Chris D. Peterson, MIT X Consortium */ #include <stdio.h> #include <ctype.h> #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include "MultiListP.h" /*===========================================================================* D E C L A R A T I O N S A N D D E F I N I T I O N S *===========================================================================*/ Pixmap XmuCreateStippledPixmap(); extern void XawInitializeWidgetSet(); #define SUPERCLASS &(simpleClassRec) #define FontAscent(f) ((f)->max_bounds.ascent) #define FontDescent(f) ((f)->max_bounds.descent) #define FontH(f) (FontAscent(f) + FontDescent(f) + 2) #define FontW(f,s) (XTextWidth(f,s,strlen(s)) + 1) #define FontMaxCharW(f) ((f)->max_bounds.rbearing-(f)->min_bounds.lbearing+1) #ifndef abs #define abs(a) ((a) < 0 ? -(a) : (a)) #endif #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) #define XtStrlen(s) ((s) ? strlen(s) : 0) #define TypeAlloc(t,n) (t *)malloc(sizeof(t) * n) #define StrCopy(s) strcpy(TypeAlloc(char,strlen(s)+1),s) #define StrCopyRetLength(s,lp) strcpy(TypeAlloc(char,(*lp=(strlen(s)+1))),s) #define CoreFieldOffset(f) XtOffset(Widget,core.f) #define SimpleFieldOffset(f) XtOffset(XfwfMultiListWidget,simple.f) #define MultiListFieldOffset(f) XtOffset(XfwfMultiListWidget,multiList.f) /*===========================================================================* I N T E R N A L P R O C E D U R E D E C L A R A T I O N S *===========================================================================*/ #if (!NeedFunctionPrototypes) static void Initialize(); static void Redisplay(); static XtGeometryResult PreferredGeometry(); static void Resize(); static Boolean SetValues(); static void DestroyOldData(); static void InitializeNewData(); static void CreateNewGCs(); static void RecalcCoords(); static void NegotiateSizeChange(); static Boolean Layout(); static void RedrawAll(); static void RedrawItem(); static void RedrawRowColumn(); static void PixelToRowColumn(); static void RowColumnToPixels(); static Boolean RowColumnToItem(); static Boolean ItemToRowColumn(); static void Select(); static void Unselect(); static void Toggle(); static void Extend(); static void Notify(); #else static void Initialize(Widget request, Widget new); static void Redisplay(XfwfMultiListWidget mlw, XEvent *event, Region rectangle_union); static XtGeometryResult PreferredGeometry(XfwfMultiListWidget mlw, XtWidgetGeometry *parent_idea, XtWidgetGeometry *our_idea); static void Resize(XfwfMultiListWidget mlw); static Boolean SetValues(XfwfMultiListWidget cpl, XfwfMultiListWidget rpl, XfwfMultiListWidget npl); static void DestroyOldData(XfwfMultiListWidget mlw); static void InitializeNewData(XfwfMultiListWidget mlw); static void CreateNewGCs(XfwfMultiListWidget mlw); static void RecalcCoords(XfwfMultiListWidget mlw, int width_changeable, int height_changeable); static void NegotiateSizeChange(XfwfMultiListWidget mlw, int width, int height); static Boolean Layout(XfwfMultiListWidget mlw, int w_changeable, int h_changeable, Dimension *w_ptr, Dimension *h_ptr); static void RedrawAll(XfwfMultiListWidget mlw); static void RedrawItem(XfwfMultiListWidget mlw, int item_index); static void RedrawRowColumn(XfwfMultiListWidget mlw, int row, int column); static void PixelToRowColumn(XfwfMultiListWidget mlw, int x, int y, int *row_ptr, int *column_ptr); static void RowColumnToPixels(XfwfMultiListWidget mlw, int row, int col, int *x_ptr, int *y_ptr, int *w_ptr, int *h_ptr); static Boolean RowColumnToItem(XfwfMultiListWidget mlw, int row, int column, int *item_ptr); static Boolean ItemToRowColumn(XfwfMultiListWidget mlw, int item_index, int *row_ptr, int *column_ptr); static void Select(XfwfMultiListWidget mlw, XEvent *event, String *params, Cardinal *num_params); static void Unselect(XfwfMultiListWidget mlw, XEvent *event, String *params, Cardinal *num_params); static void Toggle(XfwfMultiListWidget mlw, XEvent *event, String *params, Cardinal *num_params); static void Extend(XfwfMultiListWidget mlw, XEvent *event, String *params, Cardinal *num_params); static void Notify(XfwfMultiListWidget mlw, XEvent *event, String *params, Cardinal *num_params); #endif /*===========================================================================* R E S O U R C E I N I T I A L I Z A T I O N *===========================================================================*/ static XtResource resources[] = { {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), CoreFieldOffset(width), XtRString, "0"}, {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), CoreFieldOffset(height), XtRString, "0"}, {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), CoreFieldOffset(background_pixel),XtRString,"XtDefaultBackground"}, {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), SimpleFieldOffset(cursor), XtRString, "left_ptr"}, {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), MultiListFieldOffset(foreground), XtRString,"XtDefaultForeground"}, {XtNhighlightForeground, XtCHForeground, XtRPixel, sizeof(Pixel), MultiListFieldOffset(highlight_fg), XtRString, "XtDefaultBackground"}, {XtNhighlightBackground, XtCHBackground, XtRPixel, sizeof(Pixel), MultiListFieldOffset(highlight_bg), XtRString, "XtDefaultForeground"}, {XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), MultiListFieldOffset(column_space), XtRImmediate, (caddr_t)8}, {XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), MultiListFieldOffset(row_space), XtRImmediate, (caddr_t)0}, {XtNdefaultColumns, XtCColumns, XtRInt, sizeof(int), MultiListFieldOffset(default_cols), XtRImmediate, (caddr_t)1}, {XtNforceColumns, XtCColumns, XtRBoolean, sizeof(Boolean), MultiListFieldOffset(force_cols), XtRString, (caddr_t) "False"}, {XtNpasteBuffer, XtCBoolean, XtRBoolean, sizeof(Boolean), MultiListFieldOffset(paste), XtRString, (caddr_t) "False"}, {XtNverticalList, XtCBoolean, XtRBoolean, sizeof(Boolean), MultiListFieldOffset(row_major), XtRString, (caddr_t) "False"}, {XtNlongest, XtCLongest, XtRInt, sizeof(int), MultiListFieldOffset(longest), XtRImmediate, (caddr_t)0}, {XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int), MultiListFieldOffset(nitems), XtRImmediate, (caddr_t)0}, {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), MultiListFieldOffset(font),XtRString, "XtDefaultFont"}, {XtNlist, XtCList, XtRPointer, sizeof(char **), MultiListFieldOffset(list), XtRString, NULL}, {XtNsensitiveArray, XtCList, XtRPointer, sizeof(Boolean *), MultiListFieldOffset(sensitive_array), XtRString, NULL}, {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), MultiListFieldOffset(callback), XtRCallback, NULL}, {XtNmaxSelectable, XtCValue, XtRInt, sizeof(int), MultiListFieldOffset(max_selectable), XtRImmediate, (caddr_t) 1}, {XtNshadeSurplus, XtCBoolean, XtRBoolean, sizeof(Boolean), MultiListFieldOffset(shade_surplus), XtRString, "True"}, {XtNcolumnWidth, XtCValue, XtRDimension, sizeof(Dimension), MultiListFieldOffset(col_width), XtRImmediate, (caddr_t)0}, {XtNrowHeight, XtCValue, XtRDimension, sizeof(Dimension), MultiListFieldOffset(row_height), XtRImmediate, (caddr_t)0}, }; /*===========================================================================* A C T I O N A N D T R A N S L A T I O N T A B L E S *===========================================================================*/ static char defaultTranslations[] = " Shift <Btn1Down>: Toggle()\n\ Ctrl <Btn1Down>: Unselect()\n\ <Btn1Down>: Select()\n\ Button1 <Btn1Motion>: Extend()\n\ <Btn1Up>: Notify()"; static XtActionsRec actions[] = { {"Select", (XtActionProc)Select}, {"Unselect", (XtActionProc)Unselect}, {"Toggle", (XtActionProc)Toggle}, {"Extend", (XtActionProc)Extend}, {"Notify", (XtActionProc)Notify}, {NULL, (XtActionProc)NULL} }; /*===========================================================================* C L A S S A L L O C A T I O N *===========================================================================*/ XfwfMultiListClassRec xfwfMultiListClassRec = { { /* superclass */ (WidgetClass)SUPERCLASS, /* class_name */ "XfwfMultiList", /* widget_size */ sizeof(XfwfMultiListRec), /* class_initialize */ NULL, /* class_part_initialize*/ NULL, /* class_inited */ FALSE, /* initialize */ (XtInitProc)Initialize, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ FALSE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ NULL, /* resize */ (XtWidgetProc)Resize, /* expose */ (XtExposeProc)Redisplay, /* set_values */ (XtSetValuesFunc)SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ defaultTranslations, /* query_geometry */ (XtGeometryHandler) PreferredGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, /* Core Part */ { /* change_sensitive */ XtInheritChangeSensitive } }; WidgetClass xfwfMultiListWidgetClass = (WidgetClass)&xfwfMultiListClassRec; /*===========================================================================* T O O L K I T M E T H O D S *===========================================================================*/ /*---------------------------------------------------------------------------* Initialize() This procedure is called by the X toolkit to initialize the widget instance. The hook to this routine is in the initialize part of the core part of the class. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Initialize(request,new) Widget request,new; { XfwfMultiListWidget mlw; mlw = (XfwfMultiListWidget)new; CreateNewGCs(mlw); InitializeNewData(mlw); RecalcCoords(mlw,(MultiListWidth(mlw) == 0), (MultiListHeight(mlw) == 0)); } /* Initialize */ /*---------------------------------------------------------------------------* Redisplay(mlw,event,rectangle_union) This routine redraws the MultiList widget <mlw> based on the exposure region requested in <event>. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Redisplay(mlw,event,rectangle_union) XfwfMultiListWidget mlw; XEvent *event; Region rectangle_union; { GC shade_gc; int i,x1,y1,w,h,x2,y2,row,col,ul_row,ul_col,lr_row,lr_col; if (MultiListShadeSurplus(mlw)) shade_gc = MultiListGrayGC(mlw); else shade_gc = MultiListEraseGC(mlw); if (event == NULL) { XFillRectangle(XtDisplay(mlw),XtWindow(mlw),shade_gc,0,0, MultiListWidth(mlw),MultiListHeight(mlw)); for (i = 0; i < MultiListNumItems(mlw); i++) RedrawItem(mlw,i); } else { x1 = event->xexpose.x; y1 = event->xexpose.y; w = event->xexpose.width; h = event->xexpose.height; x2 = x1 + w; y2 = y1 + h; XFillRectangle(XtDisplay(mlw),XtWindow(mlw), shade_gc,x1,y1,w,h); PixelToRowColumn(mlw,x1,y1,&ul_row,&ul_col); PixelToRowColumn(mlw,x2,y2,&lr_row,&lr_col); lr_row = min(lr_row,MultiListNumRows(mlw) - 1); lr_col = min(lr_col,MultiListNumCols(mlw) - 1); for (col = ul_col; col <= lr_col; col++) { for (row = ul_row; row <= lr_row; row++) { RedrawRowColumn(mlw,row,col); } } } } /* End Redisplay */ /*---------------------------------------------------------------------------* PreferredGeometry(mlw,parent_idea,our_idea) This routine is called by the parent to tell us about the parent's idea of our width and/or height. We then suggest our preference through <our_idea> and return the information to the parent. *---------------------------------------------------------------------------*/ static XtGeometryResult PreferredGeometry(mlw,parent_idea,our_idea) XfwfMultiListWidget mlw; XtWidgetGeometry *parent_idea,*our_idea; { Dimension nw,nh; Boolean parent_wants_w,parent_wants_h,we_changed_size; parent_wants_w = (parent_idea->request_mode) & CWWidth; parent_wants_h = (parent_idea->request_mode) & CWHeight; if (parent_wants_w) nw = parent_idea->width; else nw = MultiListWidth(mlw); if (parent_wants_h) nh = parent_idea->height; else nh = MultiListHeight(mlw); our_idea->request_mode = 0; if (!parent_wants_w && !parent_wants_h) return(XtGeometryYes); we_changed_size = Layout(mlw,!parent_wants_w,!parent_wants_h,&nw,&nh); our_idea->request_mode |= (CWWidth | CWHeight); our_idea->width = nw; our_idea->height = nh; if (we_changed_size) return(XtGeometryAlmost); else return(XtGeometryYes); } /* End PreferredGeometry */ /*---------------------------------------------------------------------------* Resize(mlw) This function is called when the widget is being resized. It recalculates the layout of the widget. *---------------------------------------------------------------------------*/ static void Resize(mlw) XfwfMultiListWidget mlw; { Dimension width,height; width = MultiListWidth(mlw); height = MultiListHeight(mlw); Layout(mlw,False,False,&width,&height); } /* End Resize */ /*---------------------------------------------------------------------------* SetValues(cpl,rpl,npl) This routine is called when the user is changing resources. <cpl> is the current widget before the user's changes have been instituted. <rpl> includes the original changes as requested by the user. <npl> is the new resulting widget with the requested changes and with all superclass changes already made. *---------------------------------------------------------------------------*/ static Boolean SetValues(cpl,rpl,npl) XfwfMultiListWidget cpl,rpl,npl; { Boolean redraw,recalc; redraw = False; recalc = False; /* Graphic Context Changes */ if ((MultiListFG(cpl) != MultiListFG(npl)) || (MultiListBG(cpl) != MultiListBG(npl)) || (MultiListHighlightFG(cpl) != MultiListHighlightFG(npl)) || (MultiListHighlightBG(cpl) != MultiListHighlightBG(npl)) || (MultiListFont(cpl) != MultiListFont(npl))) { XtDestroyGC(MultiListEraseGC(cpl)); XtDestroyGC(MultiListDrawGC(cpl)); XtDestroyGC(MultiListHighlightForeGC(cpl)); XtDestroyGC(MultiListHighlightBackGC(cpl)); XtDestroyGC(MultiListGrayGC(cpl)); CreateNewGCs(npl); redraw = True; } /* Changes That Require Data Initialization */ if ((MultiListList(cpl) != MultiListList(npl)) || (MultiListSensitiveArray(cpl) != MultiListSensitiveArray(npl)) || (MultiListSensitive(cpl) != MultiListSensitive(npl)) || (MultiListAncesSensitive(cpl) != MultiListAncesSensitive(npl)) || (MultiListNumItems(cpl) != MultiListNumItems(npl)) || (MultiListMaxSelectable(cpl) != MultiListMaxSelectable(npl))) { DestroyOldData(cpl); InitializeNewData(npl); recalc = True; redraw = True; } /* Changes That Require Recalculating Coordinates */ if ((MultiListWidth(cpl) != MultiListWidth(npl)) || (MultiListHeight(cpl) != MultiListHeight(npl)) || (MultiListColumnSpace(cpl) != MultiListColumnSpace(npl)) || (MultiListRowSpace(cpl) != MultiListRowSpace(npl)) || (MultiListDefaultCols(cpl) != MultiListDefaultCols(npl)) || ((MultiListForceCols(cpl) != MultiListForceCols(npl)) && (MultiListNumCols(cpl) != MultiListNumCols(npl))) || (MultiListRowMajor(cpl) != MultiListRowMajor(npl)) || (MultiListFont(cpl) != MultiListFont(npl)) || (MultiListLongest(cpl) != MultiListLongest(npl))) { recalc = True; redraw = True; } if (MultiListColWidth(cpl) != MultiListColWidth(npl)) { XtWarning("columnWidth Resource Is Read-Only"); MultiListColWidth(npl) = MultiListColWidth(cpl); } if (MultiListRowHeight(cpl) != MultiListRowHeight(npl)) { XtWarning("rowHeight Resource Is Read-Only"); MultiListRowHeight(npl) = MultiListRowHeight(cpl); } if (recalc) { RecalcCoords(npl,!MultiListWidth(npl),!MultiListHeight(npl)); } if (!XtIsRealized((Widget)cpl)) return(False); else return(redraw); } /* End SetValues */ /*===========================================================================* D A T A I N I T I A L I Z A T I O N *===========================================================================*/ /*---------------------------------------------------------------------------* DestroyOldData(mlw) This routine frees the internal list item array and sets the item count to 0. This is normally done immediately before calling InitializeNewData() to rebuild the internal item array from new user specified arrays. *---------------------------------------------------------------------------*/ static void DestroyOldData(mlw) XfwfMultiListWidget mlw; { int i; if (MultiListItemArray(mlw) != NULL) /* Free Old List */ { for (i = 0; i < MultiListNumItems(mlw); i++) { free(MultiListItemString(MultiListNthItem(mlw,i))); } free(MultiListItemArray(mlw)); } if (MultiListSelArray(mlw) != NULL) free(MultiListSelArray(mlw)); MultiListSelArray(mlw) = NULL; MultiListNumSelected(mlw) = 0; MultiListItemArray(mlw) = NULL; MultiListNumItems(mlw) = 0; } /* End DestroyOldData */ /*---------------------------------------------------------------------------* InitializeNewData(mlw) This routine takes a MultiList widget <mlw> and builds up new data item tables based on the string list and the sensitivity array. All previous data should have already been freed. If the number of items is 0, they will be counted, so the array must be NULL terminated. If the list of strings is NULL, this is treated as a list of 0 elements. If the sensitivity array is NULL, all items are treated as sensitive. When this routine is done, the string list and sensitivity array fields will all be set to NULL, and the widget will not reference them again. *---------------------------------------------------------------------------*/ static void InitializeNewData(mlw) XfwfMultiListWidget mlw; { int i; XfwfMultiListItem *item; String *string_array; string_array = MultiListList(mlw); if (MultiListNumItems(mlw) == 0) /* Count Elements */ { if (MultiListList(mlw) == NULL) /* No elements */ { MultiListNumItems(mlw) = 0; } else { for (i = 0; string_array[i] != NULL; i++); MultiListNumItems(mlw) = i; } } if (MultiListNumItems(mlw) == 0) /* No Items */ { MultiListItemArray(mlw) = NULL; } else { MultiListItemArray(mlw) = TypeAlloc(XfwfMultiListItem,MultiListNumItems(mlw)); for (i = 0; i < MultiListNumItems(mlw); i++) { item = MultiListNthItem(mlw,i); if (MultiListSensitiveArray(mlw) == NULL || (MultiListSensitiveArray(mlw)[i] == True)) { MultiListItemSensitive(item) = True; } else { MultiListItemSensitive(item) = False; } MultiListItemString(item) = StrCopy(string_array[i]); MultiListItemHighlighted(item) = False; } } if (MultiListMaxSelectable(mlw) == 0) { MultiListSelArray(mlw) = NULL; MultiListNumSelected(mlw) = 0; } else { MultiListSelArray(mlw) = TypeAlloc(int,MultiListMaxSelectable(mlw)); MultiListNumSelected(mlw) = 0; } MultiListList(mlw) = NULL; MultiListSensitiveArray(mlw) = NULL; } /* End InitializeNewData */ /*---------------------------------------------------------------------------* CreateNewGCs(mlw) This routine takes a MultiList widget <mlw> and creates a new set of graphic contexts for the widget based on the colors, fonts, etc. in the widget. Any previous GCs are assumed to have already been destroyed. *---------------------------------------------------------------------------*/ static void CreateNewGCs(mlw) XfwfMultiListWidget mlw; { XGCValues values; unsigned int attribs; attribs = GCForeground | GCBackground | GCFont; values.foreground = MultiListFG(mlw); values.background = MultiListBG(mlw); values.font = MultiListFont(mlw)->fid; MultiListDrawGC(mlw) = XtGetGC((Widget)mlw,attribs,&values); values.foreground = MultiListBG(mlw); MultiListEraseGC(mlw) = XtGetGC((Widget)mlw,attribs,&values); values.foreground = MultiListHighlightFG(mlw); values.background = MultiListHighlightBG(mlw); MultiListHighlightForeGC(mlw) = XtGetGC((Widget)mlw,attribs,&values); values.foreground = MultiListHighlightBG(mlw); values.background = MultiListHighlightBG(mlw); MultiListHighlightBackGC(mlw) = XtGetGC((Widget)mlw,attribs,&values); attribs |= GCTile | GCFillStyle; values.foreground = MultiListFG(mlw); values.background = MultiListBG(mlw); values.fill_style = FillTiled; values.tile = XmuCreateStippledPixmap(XtScreen(mlw),MultiListFG(mlw), MultiListBG(mlw),MultiListDepth(mlw)); MultiListGrayGC(mlw) = XtGetGC((Widget)mlw,attribs,&values); } /* End CreateNewGCs */ /*===========================================================================* L A Y O U T A N D G E O M E T R Y M A N A G E M E N T *===========================================================================*/ /*---------------------------------------------------------------------------* RecalcCoords(mlw,width_changeable,height_changeable) This routine takes a MultiList widget <mlw> and recalculates the coordinates, and item placement based on the current width, height, and list of items. The <width_changeable> and <height_changeable> indicate if the width and/or height can be arbitrarily set. This routine requires that the internal list data be initialized. *---------------------------------------------------------------------------*/ static void RecalcCoords(mlw,width_changeable,height_changeable) XfwfMultiListWidget mlw; Boolean width_changeable,height_changeable; { String str; Dimension width,height; register int i,text_width; width = MultiListWidth(mlw); height = MultiListHeight(mlw); if (MultiListNumItems(mlw) != 0 && MultiListLongest(mlw) == 0) { for (i = 0; i < MultiListNumItems(mlw); i++) { str = MultiListItemString(MultiListNthItem(mlw,i)); text_width = FontW(MultiListFont(mlw),str); MultiListLongest(mlw) = max(MultiListLongest(mlw), text_width); } } if (Layout(mlw,width_changeable,height_changeable,&width,&height)) { NegotiateSizeChange(mlw,width,height); } } /* End RecalcCoords */ /*---------------------------------------------------------------------------* NegotiateSizeChange(mlw,width,height) This routine tries to change the MultiList widget <mlw> to have the new size <width> by <height>. A negotiation will takes place to try to change the size. The resulting size is not necessarily the requested size. *---------------------------------------------------------------------------*/ static void NegotiateSizeChange(mlw,width,height) XfwfMultiListWidget mlw; Dimension width,height; { int attempt_number; Boolean w_fixed,h_fixed; Dimension *w_ptr,*h_ptr; XtWidgetGeometry request,reply; request.request_mode = CWWidth | CWHeight; request.width = width; request.height = height; for (attempt_number = 1; attempt_number <= 3; attempt_number++) { switch (XtMakeGeometryRequest((Widget)mlw,&request,&reply)) { case XtGeometryYes: case XtGeometryNo: return; case XtGeometryAlmost: switch (attempt_number) { case 1: w_fixed = (request.width != reply.width); h_fixed = (request.height != reply.height); w_ptr = &(reply.width); h_ptr = &(reply.height); Layout(mlw,!w_fixed,!h_fixed,w_ptr,h_ptr); break; case 2: w_ptr = &(reply.width); h_ptr = &(reply.height); Layout(mlw,False,False,w_ptr,h_ptr); break; case 3: return; } break; default: XtAppWarning(XtWidgetToApplicationContext((Widget)mlw), "MultiList Widget: Unknown geometry return."); break; } request = reply; } } /* End NegotiateSizeChange */ /*---------------------------------------------------------------------------* Boolean Layout(mlw,w_changeable,h_changeable,w_ptr,h_ptr) This routine tries to generate a layout for the MultiList widget <mlw>. The Layout routine is free to arbitrarily set the width or height if the corresponding variables <w_changeable> and <h_changeable> are set True. Otherwise the original width or height in <w_ptr> and <h_ptr> are used as fixed values. The resulting new width and height are stored back through the <w_ptr> and <h_ptr> pointers. False is returned if no size change was done, True is returned otherwise. *---------------------------------------------------------------------------*/ static Boolean Layout(mlw,w_changeable,h_changeable,w_ptr,h_ptr) XfwfMultiListWidget mlw; Boolean w_changeable,h_changeable; Dimension *w_ptr,*h_ptr; { Boolean size_changed = False; /* * If force columns is set, then always use the number * of columns specified by default_cols. */ MultiListColWidth(mlw) = MultiListLongest(mlw) + MultiListColumnSpace(mlw); MultiListRowHeight(mlw) = FontH(MultiListFont(mlw)) + MultiListRowSpace(mlw); if (MultiListForceCols(mlw)) { MultiListNumCols(mlw) = max(MultiListDefaultCols(mlw),1); if (MultiListNumItems(mlw) == 0) MultiListNumRows(mlw) = 1; else MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) / MultiListNumCols(mlw) + 1; if (w_changeable) { *w_ptr = MultiListNumCols(mlw) * MultiListColWidth(mlw); size_changed = True; } else { MultiListColWidth(mlw) = *w_ptr / MultiListNumCols(mlw); } if (h_changeable) { *h_ptr = MultiListNumRows(mlw) * MultiListRowHeight(mlw); size_changed = True; } return(size_changed); } /* * If both width and height are free to change then use * default_cols to determine the number of columns and set * the new width and height to just fit the window. */ if (w_changeable && h_changeable) { MultiListNumCols(mlw) = max(MultiListDefaultCols(mlw),1); if (MultiListNumItems(mlw) == 0) MultiListNumRows(mlw) = 1; else MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) / MultiListNumCols(mlw) + 1; *w_ptr = MultiListNumCols(mlw) * MultiListColWidth(mlw); *h_ptr = MultiListNumRows(mlw) * MultiListRowHeight(mlw); return(True); } /* * If the width is fixed then use it to determine the * number of columns. If the height is free to move * (width still fixed) then resize the height of the * widget to fit the current MultiList exactly. */ if (!w_changeable) { MultiListNumCols(mlw) = *w_ptr / MultiListColWidth(mlw); MultiListNumCols(mlw) = max(MultiListNumCols(mlw),1); MultiListNumRows(mlw) = (MultiListNumItems(mlw) - 1) / MultiListNumCols(mlw) + 1; MultiListColWidth(mlw) = *w_ptr / MultiListNumCols(mlw); if (h_changeable) { *h_ptr = MultiListNumRows(mlw) * MultiListRowHeight(mlw); size_changed = True; } return(size_changed); } /* * The last case is xfree and !yfree we use the height to * determine the number of rows and then set the width to * just fit the resulting number of columns. */ MultiListNumRows(mlw) = *h_ptr / MultiListRowHeight(mlw); MultiListNumRows(mlw) = max(MultiListNumRows(mlw),1); MultiListNumCols(mlw) = (MultiListNumItems(mlw) - 1) / MultiListNumRows(mlw) + 1; *w_ptr = MultiListNumCols(mlw) * MultiListColWidth(mlw); return(True); } /* End Layout */ /*===========================================================================* R E D R A W R O U T I N E S *===========================================================================*/ /*---------------------------------------------------------------------------* RedrawAll(mlw) This routine simple calls Redisplay to redraw the entire MultiList widget <mlw>. *---------------------------------------------------------------------------*/ static void RedrawAll(mlw) XfwfMultiListWidget mlw; { Redisplay(mlw,NULL,NULL); } /* End RedrawAll */ /*---------------------------------------------------------------------------* RedrawItem(mlw,item_index) This routine redraws the item with index <item_index> in the MultiList widget <mlw>. If the item number is bad, nothing is drawn. *---------------------------------------------------------------------------*/ static void RedrawItem(mlw,item_index) XfwfMultiListWidget mlw; int item_index; { int row,column; if (ItemToRowColumn(mlw,item_index,&row,&column)) { RedrawRowColumn(mlw,row,column); } } /* End RedrawItem */ /*---------------------------------------------------------------------------* RedrawRowColumn(mlw,row,column) This routine paints the item in row/column position <row>,<column> on the MultiList widget <mlw>. If the row/column coordinates are outside the widget, nothing is drawn. If the position is empty, blank space is drawn. *---------------------------------------------------------------------------*/ static void RedrawRowColumn(mlw,row,column) XfwfMultiListWidget mlw; int row,column; { GC bg_gc,fg_gc; XfwfMultiListItem *item; int ul_x,ul_y,str_x,str_y,w,h,item_index,has_item,text_h; if (!XtIsRealized((Widget)mlw)) return; has_item = RowColumnToItem(mlw,row,column,&item_index); RowColumnToPixels(mlw,row,column,&ul_x,&ul_y,&w,&h); if (has_item == False) /* No Item */ { if (MultiListShadeSurplus(mlw)) bg_gc = MultiListGrayGC(mlw); else bg_gc = MultiListEraseGC(mlw); } else { item = MultiListNthItem(mlw,item_index); if (!MultiListItemSensitive(item)) /* Disabled */ { bg_gc = MultiListEraseGC(mlw); fg_gc = MultiListGrayGC(mlw); } else if (MultiListItemHighlighted(item)) /* Selected */ { bg_gc = MultiListHighlightBackGC(mlw); fg_gc = MultiListHighlightForeGC(mlw); } else /* Normal */ { bg_gc = MultiListEraseGC(mlw); fg_gc = MultiListDrawGC(mlw); } } XFillRectangle(XtDisplay(mlw),XtWindow(mlw),bg_gc,ul_x,ul_y,w,h); if (has_item == True) { text_h = min(FontH(MultiListFont(mlw)) + MultiListRowSpace(mlw),MultiListRowHeight(mlw)); str_x = ul_x + MultiListColumnSpace(mlw) / 2; str_y = ul_y + FontAscent(MultiListFont(mlw)) + (MultiListRowHeight(mlw) - text_h) / 2; XDrawString(XtDisplay(mlw),XtWindow(mlw),fg_gc, str_x,str_y,MultiListItemString(item), strlen(MultiListItemString(item))); } } /* End RedrawRowColumn */ /*===========================================================================* I T E M L O C A T I O N R O U T I N E S *===========================================================================*/ /*---------------------------------------------------------------------------* void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr) This routine takes pixel coordinates <x>, <y> and converts the pixel coordinate into a row/column coordinate. This row/column coordinate can then easily be converted into the specific item in the list via the function RowColumnToItem(). If the pixel lies in blank space outside of the items, the row & column numbers will be outside of the range of normal row & columns numbers, but will correspond to the row & column of the item, if an item was actually there. *---------------------------------------------------------------------------*/ static void PixelToRowColumn(mlw,x,y,row_ptr,column_ptr) XfwfMultiListWidget mlw; int x,y,*row_ptr,*column_ptr; { *row_ptr = y / MultiListRowHeight(mlw); *column_ptr = x / MultiListColWidth(mlw); } /* End PixelToRowColumn */ /*---------------------------------------------------------------------------* void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr) This routine takes a row/column coordinate <row>,<col> and converts it into the bounding pixel rectangle which is returned. *---------------------------------------------------------------------------*/ static void RowColumnToPixels(mlw,row,col,x_ptr,y_ptr,w_ptr,h_ptr) XfwfMultiListWidget mlw; int row,col,*x_ptr,*y_ptr,*w_ptr,*h_ptr; { *x_ptr = col * MultiListColWidth(mlw); *y_ptr = row * MultiListRowHeight(mlw); *w_ptr = MultiListColWidth(mlw); *h_ptr = MultiListRowHeight(mlw); } /* End RowColumnToPixels */ /*---------------------------------------------------------------------------* Boolean RowColumnToItem(mlw,row,column,item_ptr) This routine takes a row number <row> and a column number <column> and tries to resolve this row and column into the index of the item in this position of the MultiList widget <mlw>. The resulting item index is placed through <item_ptr>. If there is no item at this location, False is returned, else True is returned. *---------------------------------------------------------------------------*/ static Boolean RowColumnToItem(mlw,row,column,item_ptr) XfwfMultiListWidget mlw; int row,column,*item_ptr; { register int x_stride,y_stride; if (row < 0 || row >= MultiListNumRows(mlw) || column < 0 || column >= MultiListNumCols(mlw)) { return(False); } if (MultiListRowMajor(mlw)) { x_stride = 1; y_stride = MultiListNumCols(mlw); } else { x_stride = MultiListNumRows(mlw); y_stride = 1; } *item_ptr = row * y_stride + column * x_stride; if (*item_ptr >= MultiListNumItems(mlw)) return(False); else return(True); } /* End RowColumnToItem */ /*---------------------------------------------------------------------------* Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr) This routine takes an item number <item_index> and attempts to convert the index into row and column numbers stored through <row_ptr> and <column_ptr>. If the item number does not corespond to a valid item, False is returned, else True is returned. *---------------------------------------------------------------------------*/ static Boolean ItemToRowColumn(mlw,item_index,row_ptr,column_ptr) XfwfMultiListWidget mlw; int item_index,*row_ptr,*column_ptr; { if (item_index < 0 || item_index >= MultiListNumItems(mlw)) { return(False); } if (MultiListRowMajor(mlw)) { *row_ptr = item_index / MultiListNumCols(mlw); *column_ptr = item_index % MultiListNumCols(mlw); } else { *row_ptr = item_index % MultiListNumRows(mlw); *column_ptr = item_index / MultiListNumRows(mlw); } return(True); } /* End ItemToRowColumn */ /*===========================================================================* E V E N T A C T I O N H A N D L E R S *===========================================================================*/ /*---------------------------------------------------------------------------* Select(mlw,event,params,num_params) This action handler is called when a user selects an item in the MultiList. This action first unselects all previously selected items, then selects the item under the mouse, if it is not a background gap, and if it is sensitive. The MultiListMostRecentItem(mlw) variable will be set to the item clicked on, or -1 if the item is background or insensitive. The MultiListMostRecentAct(mlw) variable will be set to XfwfMultiListActionHighlight, in case the selection region is extended. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Select(mlw,event,params,num_params) XfwfMultiListWidget mlw; XEvent *event; String *params; Cardinal *num_params; { int click_x,click_y; int status,item_index,row,column; click_x = event->xbutton.x; click_y = event->xbutton.y; PixelToRowColumn(mlw,click_x,click_y,&row,&column); XfwfMultiListUnhighlightAll(mlw); MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight; status = RowColumnToItem(mlw,row,column,&item_index); if ((status == False) || (!MultiListItemSensitive(MultiListNthItem(mlw,item_index)))) { MultiListMostRecentItem(mlw) = -1; } else { MultiListMostRecentItem(mlw) = item_index; XfwfMultiListHighlightItem(mlw,item_index); } } /* End Select */ /*---------------------------------------------------------------------------* Unselect(mlw,event,params,num_params) This function unselects the single text item pointed to by the mouse, if any. Any remaining selected entries are left selected. The MultiListMostRecentItem(mlw) variable will be set to -1, and the MultiListMostRecentAct(mlw) variable will be set to XfwfMultiListActionUnhighlight, in case the deselection region is extended. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Unselect(mlw,event,params,num_params) XfwfMultiListWidget mlw; XEvent *event; String *params; Cardinal *num_params; { int click_x,click_y; int status,item_index,row,column; click_x = event->xbutton.x; click_y = event->xbutton.y; PixelToRowColumn(mlw,click_x,click_y,&row,&column); MultiListMostRecentItem(mlw) = -1; MultiListMostRecentAct(mlw) = XfwfMultiListActionUnhighlight; status = RowColumnToItem(mlw,row,column,&item_index); if ((status == True) && (MultiListItemSensitive(MultiListNthItem(mlw,item_index)))) XfwfMultiListHighlightItem(mlw,item_index); } /* End Unselect */ /*---------------------------------------------------------------------------* Toggle(mlw,event,params,num_params) This action handler implements the toggling of selection status for a single item. Any remaining selected entries are left selected. If the mouse is not over a selectable text item, the MultiListMostRecentAct(mlw) variable is set to XfwfMultiListActionHighlight, in case the region is extended into selectable items later. MultiListMostRecentItem(mlw) is set to -1. If the mouse is over a selectable text item, the item highlight is toggled. If the item is currently selected, it becomes deselected. If unselected, the item becomes selected. At the same time, the MultiListMostRecentAct(mlw) variable is set to XfwfMultiListActionHighlight if the item was not previously selected, or XfwfMultiListActionUnhighlight if the item was previously selected. MultiListMostRecentItem(mlw) is set to the index of the item clicked on if the item is selected, or -1 if it is unselected. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Toggle(mlw,event,params,num_params) XfwfMultiListWidget mlw; XEvent *event; String *params; Cardinal *num_params; { int click_x,click_y; int status,item_index,row,column; click_x = event->xbutton.x; click_y = event->xbutton.y; PixelToRowColumn(mlw,click_x,click_y,&row,&column); status = RowColumnToItem(mlw,row,column,&item_index); if ((status == False) || (!MultiListItemSensitive(MultiListNthItem(mlw,item_index)))) { MultiListMostRecentAct(mlw) = XfwfMultiListActionHighlight; MultiListMostRecentItem(mlw) = -1; } else { MultiListMostRecentAct(mlw) = XfwfMultiListToggleItem(mlw,item_index); MultiListMostRecentItem(mlw) = item_index; } } /* End Toggle */ /*---------------------------------------------------------------------------* Extend(mlw,event,params,num_params) This action handler implements the extension of a selection/ deselection region. The MultiListMostRecentAct(mlw) variable is used to determine if items are to be selected or unselected. This routine performs select or unselect actions on each item it is called on. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Extend(mlw,event,params,num_params) XfwfMultiListWidget mlw; XEvent *event; String *params; Cardinal *num_params; { int click_x,click_y; int status,item_index,row,column; click_x = ((XMotionEvent*)event)->x; click_y = ((XMotionEvent*)event)->y; PixelToRowColumn(mlw,click_x,click_y,&row,&column); status = RowColumnToItem(mlw,row,column,&item_index); if ((status == True) && (MultiListItemSensitive(MultiListNthItem(mlw,item_index)))) { MultiListMostRecentItem(mlw) = item_index; if (MultiListMostRecentAct(mlw) == XfwfMultiListActionHighlight) XfwfMultiListHighlightItem(mlw,item_index); else XfwfMultiListUnhighlightItem(mlw,item_index); } } /* End Extend */ /*---------------------------------------------------------------------------* Notify(mlw,event,params,num_params) This function performs the Notify action, which issues a callback after a selection/unselection has completed. All callbacks on the callback list are invoked, and a XfxfMultiListReturnStruct describing the selection state is returned. In addition, if the XtNpasteBuffer resource is true and at least one text item is selected, all the selected items are placed in the X cut buffer (buf(0)) separated by newlines. *---------------------------------------------------------------------------*/ /* ARGSUSED */ static void Notify(mlw,event,params,num_params) XfwfMultiListWidget mlw; XEvent *event; String *params; Cardinal *num_params; { char *buffer; String string; int i,byte_count,item_index; XfwfMultiListReturnStruct ret_value; if ((MultiListNumSelected(mlw) != 0) && MultiListPaste(mlw)) { byte_count = 0; for (i = 0; i < MultiListNumSelected(mlw); i++) { item_index = MultiListSelArray(mlw)[i]; string = MultiListItemString(MultiListNthItem(mlw, item_index)); byte_count = byte_count + strlen(string) + 1; } buffer = (char *)malloc(byte_count); buffer[0] = '\0'; for (i = 0; i < MultiListNumSelected(mlw); i++) { if (i != 0) strcat(buffer,"\n"); item_index = MultiListSelArray(mlw)[i]; string = MultiListItemString(MultiListNthItem(mlw, item_index)); strcat(buffer,string); } XStoreBytes(XtDisplay(mlw),buffer,byte_count); free(buffer); } ret_value.action = MultiListMostRecentAct(mlw); ret_value.item = MultiListMostRecentItem(mlw); if (ret_value.item == -1) ret_value.string = NULL; else ret_value.string = MultiListItemString(MultiListNthItem(mlw, ret_value.item)); ret_value.num_selected = MultiListNumSelected(mlw); ret_value.selected_items = MultiListSelArray(mlw); XtCallCallbacks((Widget)mlw,XtNcallback,(caddr_t)&ret_value); } /* End Notify */ /*===========================================================================* U S E R C A L L A B L E U T I L I T Y R O U T I N E S *===========================================================================*/ /*---------------------------------------------------------------------------* Boolean XfwfMultiListHighlightItem(mlw,item_index) This routine selects an item with index <item_index> in the MultiList widget <mlw>. If a maximum number of selections is specified and exceeded, the earliest selection will be unselected. If <item_index> doesn't correspond to an item the most recently clicked item will be set to -1 and this routine will immediately return, otherwise the most recently clicked item will be set to the current item. If the clicked on item is not sensitive, or if the click is not on an item, False is returned, else True is returned. *---------------------------------------------------------------------------*/ Boolean XfwfMultiListHighlightItem(mlw,item_index) XfwfMultiListWidget mlw; int item_index; { XfwfMultiListItem *item; if (MultiListMaxSelectable(mlw) == 0) return(False); if (item_index < 0 || item_index >= MultiListNumItems(mlw)) { MultiListMostRecentItem(mlw) = -1; return(False); } item = MultiListNthItem(mlw,item_index); if (MultiListItemSensitive(item) == False) return(False); MultiListMostRecentItem(mlw) = item_index; if (MultiListItemHighlighted(item) == True) return(True); if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw)) { XfwfMultiListUnhighlightItem(mlw,MultiListSelArray(mlw)[0]); } MultiListItemHighlighted(item) = True; MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = item_index; ++ MultiListNumSelected(mlw); RedrawItem(mlw,item_index); return(True); } /* End XfwfMultiListHighlightItem */ /*---------------------------------------------------------------------------* XfwfMultiListHighlightAll(mlw) This routine highlights all highlightable items in the MultiList widget <mlw>, up to the maximum number of allowed highlightable items; *---------------------------------------------------------------------------*/ void XfwfMultiListHighlightAll(mlw) XfwfMultiListWidget mlw; { int i; XfwfMultiListItem *item; MultiListNumSelected(mlw) = 0; for (i = 0; i < MultiListNumItems(mlw); i++) { item = MultiListNthItem(mlw,i); MultiListItemHighlighted(item) = False; } for (i = 0; i < MultiListNumItems(mlw); i++) { if (MultiListNumSelected(mlw) == MultiListMaxSelectable(mlw)) break; item = MultiListNthItem(mlw,i); if (MultiListItemSensitive(item) == False) continue; MultiListItemHighlighted(item) = True; MultiListSelArray(mlw)[MultiListNumSelected(mlw)] = i; ++ MultiListNumSelected(mlw); } RedrawAll(mlw); } /* End XfwfMultiListHighlightAll */ /*---------------------------------------------------------------------------* XfwfMultiListUnhighlightItem(mlw,item_index) This routine unselects the item with index <item_index> in the MultiList widget <mlw>. If <item_index> doesn't correspond to a selected item, then nothing will happen. Otherwise, the item is unselected and the selection array and count are updated. *---------------------------------------------------------------------------*/ void XfwfMultiListUnhighlightItem(mlw,item_index) XfwfMultiListWidget mlw; int item_index; { int i; XfwfMultiListItem *item; if (MultiListMaxSelectable(mlw) == 0) return; if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return; item = MultiListNthItem(mlw,item_index); if (MultiListItemHighlighted(item) == False) return; MultiListItemHighlighted(item) = False; for (i = 0; i < MultiListNumSelected(mlw); i++) if (MultiListSelArray(mlw)[i] == item_index) break; for (i = i + 1; i < MultiListNumSelected(mlw); i++) MultiListSelArray(mlw)[i - 1] = MultiListSelArray(mlw)[i]; -- MultiListNumSelected(mlw); RedrawItem(mlw,item_index); } /* End XfwfMultiListUnhighlightItem */ /*---------------------------------------------------------------------------* XfwfMultiListUnhighlightAll(mlw) This routine unhighlights all items in the MultiList widget <mlw>. *---------------------------------------------------------------------------*/ void XfwfMultiListUnhighlightAll(mlw) XfwfMultiListWidget mlw; { int i; XfwfMultiListItem *item; for (i = 0; i < MultiListNumItems(mlw); i++) { item = MultiListNthItem(mlw,i); if (MultiListItemHighlighted(item)) XfwfMultiListUnhighlightItem(mlw,i); } MultiListNumSelected(mlw) = 0; } /* End XfwfMultiListUnhighlightAll */ /*---------------------------------------------------------------------------* int XfwfMultiListToggleItem(mlw,item_index) This routine highlights the item with index <item_index> if it is unhighlighted and unhighlights it if it is already highlighted. The action performed by the toggle is returned (XfwfMultiListActionHighlight or XfwfMultiListActionUnhighlight). *---------------------------------------------------------------------------*/ int XfwfMultiListToggleItem(mlw,item_index) XfwfMultiListWidget mlw; int item_index; { XfwfMultiListItem *item; if (MultiListMaxSelectable(mlw) == 0) return(XfwfMultiListActionNothing); if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return(XfwfMultiListActionNothing); item = MultiListNthItem(mlw,item_index); if (MultiListItemSensitive(item) == False) return(XfwfMultiListActionNothing); if (MultiListItemHighlighted(item)) { XfwfMultiListUnhighlightItem(mlw,item_index); return(XfwfMultiListActionUnhighlight); } else { XfwfMultiListHighlightItem(mlw,item_index); return(XfwfMultiListActionHighlight); } } /* End XfwfMultiListToggleItem */ /*---------------------------------------------------------------------------* XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw) This routine takes a MultiList widget <mlw> and returns a XfwfMultiListReturnStruct whose num_selected and selected_items fields contain the highlight information. The action field is set to MULTILIST_ACTION_STATUS, and the item_index and string fields are invalid. *---------------------------------------------------------------------------*/ XfwfMultiListReturnStruct *XfwfMultiListGetHighlighted(mlw) XfwfMultiListWidget mlw; { XfwfMultiListItem *item; static XfwfMultiListReturnStruct ret_value; ret_value.action = XfwfMultiListActionStatus; if (MultiListNumSelected(mlw) == 0) { ret_value.item = -1; ret_value.string = NULL; } else { ret_value.item = MultiListSelArray(mlw) [MultiListNumSelected(mlw) - 1]; item = MultiListNthItem(mlw,ret_value.item); ret_value.string = MultiListItemString(item); } ret_value.num_selected = MultiListNumSelected(mlw); ret_value.selected_items = MultiListSelArray(mlw); return(&ret_value); } /* End XfwfMultiListGetHighlighted */ /*---------------------------------------------------------------------------* Boolean XfwfMultiListIsHighlighted(mlw,item_index) This routine checks if the item with index <item_index> is highlighted and returns True or False depending. If <item_index> is invalid, False is returned. *---------------------------------------------------------------------------*/ Boolean XfwfMultiListIsHighlighted(mlw,item_index) XfwfMultiListWidget mlw; int item_index; { XfwfMultiListItem *item; if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return(False); item = MultiListNthItem(mlw,item_index); return(MultiListItemHighlighted(item)); } /* End XfwfMultiListIsHighlighted */ /*---------------------------------------------------------------------------* Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr) This routine returns the string, highlight status and sensitivity information for the item with index <item_index> via the pointers <str_ptr>, <h_ptr> and <s_ptr>. If the item index is invalid, False is returned, else True is returned. *---------------------------------------------------------------------------*/ Boolean XfwfMultiListGetItemInfo(mlw,item_index,str_ptr,h_ptr,s_ptr) XfwfMultiListWidget mlw; int item_index; String *str_ptr; Boolean *h_ptr,*s_ptr; { XfwfMultiListItem *item; if (item_index < 0 || item_index >= MultiListNumItems(mlw)) return(False); item = MultiListNthItem(mlw,item_index); *str_ptr = MultiListItemString(item); *h_ptr = MultiListItemHighlighted(item); *s_ptr = MultiListItemSensitive(item); return(True); } /* End XfwfMultiListGetItemInfo */ /*---------------------------------------------------------------------------* XfwfMultiListSetNewData(mlw,list,nitems,longest,resize, sensitivity_array) This routine will set a new set of strings <list> into the MultiList widget <mlw>. If <resize> is True, the MultiList widget will try to resize itself. *---------------------------------------------------------------------------*/ void XfwfMultiListSetNewData(mlw,list,nitems,longest,resize,sensitivity_array) XfwfMultiListWidget mlw; String *list; int nitems,longest; Boolean resize; Boolean *sensitivity_array; { DestroyOldData(mlw); MultiListList(mlw) = list; MultiListNumItems(mlw) = max(nitems,0); MultiListLongest(mlw) = max(longest,0); MultiListSensitiveArray(mlw) = sensitivity_array; InitializeNewData(mlw); RecalcCoords(mlw,resize,resize); if (XtIsRealized((Widget)mlw)) Redisplay(mlw,NULL,NULL); } /* End XfwfMultiListSetNewData */ SHAR_EOF fi if test -f 'MultiList.h' then echo shar: "will not over-write existing file 'MultiList.h'" else cat << \SHAR_EOF > 'MultiList.h' /**************************************************************************** MultiList.h This file is the public header file for the MultiList widget, an extension to the Athena List widget. This code is loosely based on the Athena List source which is why the MIT copyright notice appears below. The code was changed substantially in V3.4 to change the action/callback interface which was unnecessarily ugly. Code using some features of the old interface may need to be changed. Hope the changes don't make people's lives too miserable. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ /* * Copyright 1989 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Original Athena Author: Chris D. Peterson, MIT X Consortium */ #ifndef _MULTILIST_H_ #define _MULTILIST_H_ #include <X11/Xaw/Simple.h> /*---------------------------------------------------------------------------* R E S O U R C E D E S C R I P T I O N S A N D N O T E S *---------------------------------------------------------------------------*/ /* Name Class RepType Default Value ---- ----- ------- ------------- background Background Pixel XtDefaultBackground border BorderColor Pixel XtDefaultForeground borderWidth BorderWidth Dimension 1 callback Callback XtCallbackList NULL *1 columnWidth Width Dimension 0 *9 columnSpacing Spacing Dimension 8 cursor Cursor Cursor left_ptr defaultColumns Columns int 1 *2 destroyCallback Callback Pointer NULL font Font XFontStruct* XtDefaultFont forceColumns Columns Boolean False *2 foreground Foreground Pixel XtDefaultForeground height Height Dimension 0 *3 highlightBackground HBackground Pixel XtDefaultForeground *4 highlightForeground HForeground Pixel XtDefaultBackground *4 insensitiveBorder Insensitive Pixmap Gray list List String * NULL *5 longest Longest int 0 *6 mappedWhenManaged MappedWhenManaged Boolean True maxSelectable Value int 1 *7 numberStrings NumberStrings int 0 *5 pasteBuffer Boolean Boolean False rowHeight Height Dimension 0 *9 rowSpacing Spacing Dimension 2 sensitive Sensitive Boolean True sensitiveArray List Boolean * NULL *8 shadeSurplus Boolean Boolean True *10 verticalList Boolean Boolean False width Width Dimension 0 x Position Position 0 y Position Position 0 *1 - The callback functions are called whenever a highlight or unhighlight takes place. More precisely, a callback occurs whenever the Notify() action is triggered. By default, this occurs when the mouse button is lifted after a selection or deselection occurred. The callback returns an XfwfMultiListReturnStruct data structure which contains numerous fields describing the selection state. The most important fields indicate the total number of items selected, and a list of those items. *2 - The defaultColumns resource is used in two cases. If forceColumns is true, the widget will set the number of columns to the value of default columns. If the widget width is unconstrained by the parent widgets, the defaultColumns is also used to determine the number of columns and the resulting width. Otherwise, the number of columns will be calcultaed based on the current width and will be changed to an appropriate value. *3 - If the width or height is set to zero (0), which is the default case, then the widget will calculate the size of that dimension to be just large enough to hold the contents of the widget. *4 - The highlightForeground and highlightBackground colors specify the colors used to highlight the text (foreground) and the surrounding background space of a list item when it is selected (highlighted). The default is the reverse of the default foreground and background colors. *5 - The list resource is an array of strings (char * array) which tell the names of each item of the list. The number of elements of this array are indicated by the resource numberStrings. If numberStrings is set to 0 (the default), then the MultiList widget will count the number of strings in the list. This requires that the list be NULL terminated. If list is NULL, then the widget treats it as an empty list. Once the list is set the list resource is set to NULL, so you won't be able to read back the list after it has been set. The widgets copies the strings internally, so the user can free the list storage after setting it. *6 - This resource represent the longest string in pixels. If this resource is zero (0), which is the default and probably the value most people should use, the longest string length is calculated and the resource is updated. *7 - The maxSelectable resource indicates the maximum number of items which can be selected at any one time. In the original Athena widget, you could have at most one item selected at a time. In this widget, you can choose how many will be selected at a time. *8 - Each item in the MultiList can be made insensitive, so it is printed in gray shading and can not be highlighted. This can be done by setting the sensitivity list, which is an array of Booleans which indicate whether or not the corresponding item is sensitive (can be selected). If sensitivity list is NULL, all items are sensitive. The widget copies the sensitivity information, so the user can delete the sensitivity array storage after setting it. The widget sets the resource to NULL after it has been set, so the user cannot read the old list back. *9 - These values are intended for reading only. They indicate the pixel width/height of the column/row. *10 - If the list height is made larger than the sum of the list entry heights, the surplus space is shaded in the background color if shadeSurplus is False, or in a gray stipple pattern if shadeSurplus is True. */ /*---------------------------------------------------------------------------* S T R I N G D E F I N I T I O N S *---------------------------------------------------------------------------*/ #define XtCList "List" #define XtCSpacing "Spacing" #define XtCColumns "Columns" #define XtCLongest "Longest" #define XtCNumberStrings "NumberStrings" #define XtCHForeground "HForeground" #define XtCHBackground "HBackground" #ifndef XtNcursor #define XtNcursor "cursor" #endif #define XtNhighlightForeground "highlightForeground" #define XtNhighlightBackground "highlightBackground" #define XtNcolumnSpacing "columnSpacing" #define XtNrowSpacing "rowSpacing" #define XtNdefaultColumns "defaultColumns" #define XtNforceColumns "forceColumns" #define XtNpasteBuffer "pasteBuffer" #define XtNverticalList "verticalList" #define XtNlongest "longest" #define XtNnumberStrings "numberStrings" #define XtNlist "list" #define XtNsensitiveArray "sensitiveArray" #define XtNmaxSelectable "maxSelectable" #define XtNshadeSurplus "shadeSurplus" #define XtNrowHeight "rowHeight" #define XtNcolumnWidth "columnWidth" /* Class Record Constants */ extern WidgetClass xfwfMultiListWidgetClass; typedef struct _XfwfMultiListClassRec *XfwfMultiListWidgetClass; typedef struct _XfwfMultiListRec *XfwfMultiListWidget; /*---------------------------------------------------------------------------* R E T U R N S T R U C T U R E *---------------------------------------------------------------------------*/ #define XfwfMultiListActionNothing 0 #define XfwfMultiListActionHighlight 1 #define XfwfMultiListActionUnhighlight 2 #define XfwfMultiListActionStatus 3 typedef struct _XfwfMultiListReturnStruct { int num_selected; /* Number Of Items Now Selected */ int *selected_items; /* Indexes Of Selected Items */ int action; /* Last Action Performed */ int item; /* Last Item Index Modified */ String string; /* String Of Last Index Modified */ } XfwfMultiListReturnStruct; /*---------------------------------------------------------------------------* U T I L I T Y R O U T I N E S *---------------------------------------------------------------------------*/ #if (!NeedFunctionPrototypes) extern Boolean XfwfMultiListHighlightItem(); extern void XfwfMultiListHighlightAll(); extern void XfwfMultiListUnhighlightItem(); extern void XfwfMultiListUnhighlightAll(); extern int XfwfMultiListToggleItem(); extern XfwfMultiListReturnStruct * XfwfMultiListGetHighlighted(); extern Boolean XfwfMultiListIsHighlighted(); extern Boolean XfwfMultiListGetItemInfo(); extern void XfwfMultiListSetNewData(); #else extern Boolean XfwfMultiListHighlightItem(XfwfMultiListWidget mlw, int item_index); extern void XfwfMultiListHighlightAll(XfwfMultiListWidget mlw); extern void XfwfMultiListUnhighlightItem(XfwfMultiListWidget mlw, int item_index); extern void XfwfMultiListUnhighlightAll(XfwfMultiListWidget mlw); extern int XfwfMultiListToggleItem(XfwfMultiListWidget mlw, int item_index); extern XfwfMultiListReturnStruct * XfwfMultiListGetHighlighted(XfwfMultiListWidget mlw); extern Boolean XfwfMultiListIsHighlighted(XfwfMultiListWidget mlw, int item_index); extern Boolean XfwfMultiListGetItemInfo(XfwfMultiListWidget mlw, int item_index, String *str_ptr, Boolean *h_ptr, Boolean *s_ptr); extern void XfwfMultiListSetNewData(XfwfMultiListWidget mlw, String *list, int nitems, int longest, int resize, Boolean *sensitivity_array); #endif #endif SHAR_EOF fi if test -f 'MultiListP.h' then echo shar: "will not over-write existing file 'MultiListP.h'" else cat << \SHAR_EOF > 'MultiListP.h' /**************************************************************************** MultiListP.h This file is the private header file for the MultiList widget, an extension to the Athena List widget. This code is loosely based on the Athena List source which is why the MIT copyright notice appears below. The code was changed substantially in V3.4 to change the action/callback interface which was unnecessarily ugly. Code using some features of the old interface may need to be changed. Hope the changes don't make people's lives too miserable. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ /* * Copyright 1989 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Original Athena Author: Chris D. Peterson, MIT X Consortium */ #ifndef _MULTILISTP_H_ #define _MULTILISTP_H_ #include <X11/Xaw/SimpleP.h> #include "MultiList.h" /*---------------------------------------------------------------------------* L O C A L D A T A S T R U C T U R E D E F I N I T I O N S *---------------------------------------------------------------------------*/ typedef struct { Boolean sensitive; Boolean highlighted; String string; } XfwfMultiListItem; /*---------------------------------------------------------------------------* W I D G E T D A T A S T R U C T U R E D E F I N I T I O N S *---------------------------------------------------------------------------*/ typedef struct { int foo; } XfwfMultiListClassPart; typedef struct _XfwfMultiListClassRec { CoreClassPart core_class; SimpleClassPart simple_class; XfwfMultiListClassPart multiList_class; } XfwfMultiListClassRec; extern XfwfMultiListClassRec xfwfMultiListClassRec; typedef struct { Pixel foreground; Pixel highlight_fg; Pixel highlight_bg; Dimension column_space; Dimension row_space; int default_cols; Boolean force_cols; Boolean paste; Boolean row_major; int longest; int nitems; XFontStruct *font; String *list; Boolean *sensitive_array; XtCallbackList callback; int max_selectable; Boolean shade_surplus; Dimension col_width; Dimension row_height; int right_padding; int bottom_padding; int nrows; int ncols; int most_recent_clicked_item; int most_recent_action; GC erase_gc; GC draw_gc; GC highlight_bg_gc; GC highlight_fg_gc; GC gray_gc; XfwfMultiListItem *item_array; int num_selected; int *sel_array; } XfwfMultiListPart; typedef struct _XfwfMultiListRec { CorePart core; SimplePart simple; XfwfMultiListPart multiList; } XfwfMultiListRec; /*---------------------------------------------------------------------------* D A T A S T R U C T U R E A C C E S S M A C R O S *---------------------------------------------------------------------------*/ #define MultiListItemSensitive(i) ((i)->sensitive) #define MultiListItemHighlighted(i) ((i)->highlighted) #define MultiListItemString(i) ((i)->string) #define InstanceCore(w) (&((w)->core)) #define InstanceSimple(w) (&((w)->simple)) #define InstanceMultiList(w) (&((w)->multiList)) #define MultiListWidth(w) (InstanceCore(w)->width) #define MultiListHeight(w) (InstanceCore(w)->height) #define MultiListBG(w) (InstanceCore(w)->background_pixel) #define MultiListSensitive(w) (InstanceCore(w)->sensitive) #define MultiListAncesSensitive(w) (InstanceCore(w)->ancestor_sensitive) #define MultiListDepth(w) (InstanceCore(w)->depth) #define MultiListFG(w) (InstanceMultiList(w)->foreground) #define MultiListHighlightFG(w) (InstanceMultiList(w)->highlight_fg) #define MultiListHighlightBG(w) (InstanceMultiList(w)->highlight_bg) #define MultiListColumnSpace(w) (InstanceMultiList(w)->column_space) #define MultiListRowSpace(w) (InstanceMultiList(w)->row_space) #define MultiListDefaultCols(w) (InstanceMultiList(w)->default_cols) #define MultiListForceCols(w) (InstanceMultiList(w)->default_cols) #define MultiListPaste(w) (InstanceMultiList(w)->paste) #define MultiListRowMajor(w) (InstanceMultiList(w)->row_major) #define MultiListLongest(w) (InstanceMultiList(w)->longest) #define MultiListNumItems(w) (InstanceMultiList(w)->nitems) #define MultiListFont(w) (InstanceMultiList(w)->font) #define MultiListList(w) (InstanceMultiList(w)->list) #define MultiListSensitiveArray(w) (InstanceMultiList(w)->sensitive_array) #define MultiListCallback(w) (InstanceMultiList(w)->callback) #define MultiListMaxSelectable(w) (InstanceMultiList(w)->max_selectable) #define MultiListShadeSurplus(w) (InstanceMultiList(w)->shade_surplus) #define MultiListColWidth(w) (InstanceMultiList(w)->col_width) #define MultiListRowHeight(w) (InstanceMultiList(w)->row_height) #define MultiListRightPadding(w) (InstanceMultiList(w)->right_padding) #define MultiListBottomPadding(w) (InstanceMultiList(w)->bottom_padding) #define MultiListNumRows(w) (InstanceMultiList(w)->nrows) #define MultiListNumCols(w) (InstanceMultiList(w)->ncols) #define MultiListMostRecentItem(w) (InstanceMultiList(w)->most_recent_clicked_item) #define MultiListMostRecentAct(w) (InstanceMultiList(w)->most_recent_action) #define MultiListEraseGC(w) (InstanceMultiList(w)->erase_gc) #define MultiListDrawGC(w) (InstanceMultiList(w)->draw_gc) #define MultiListHighlightForeGC(w) (InstanceMultiList(w)->highlight_fg_gc) #define MultiListHighlightBackGC(w) (InstanceMultiList(w)->highlight_bg_gc) #define MultiListGrayGC(w) (InstanceMultiList(w)->gray_gc) #define MultiListItemArray(w) (InstanceMultiList(w)->item_array) #define MultiListNthItem(w,n) (&(MultiListItemArray(w)[n])) #define MultiListSelArray(w) (InstanceMultiList(w)->sel_array) #define MultiListNumSelected(w) (InstanceMultiList(w)->num_selected) #endif SHAR_EOF fi if test -f 'Prop.lst' then echo shar: "will not over-write existing file 'Prop.lst'" else cat << \SHAR_EOF > 'Prop.lst' Smart-Go Properties mgt supports x "B" : Black move [move] x "W" : White move [move] x "C" : Comment [Text] x "N" : Node Name [Text] "V" : Node value [number] "CH": Check mark [triple] "GB": good for black [triple] "GW": good for white [triple] "TE": good move (tesuji) [triple] "BM": bad move [triple] "BL": time left for Black [real] "WL": time left for White [real] "FG": figure [none] x "AB": add black stones [point list] x "AW": add white stones [point list] x "AE": add empty stones [point list] x "PL": player to play first [color] x "GN": game name [text] x "GC": game comment [text] x "EV": event (tournament) [text] x "RO": round [text] x "DT": date [text] x "PC": place [text] x "PB": black player name [text] x "PW": white player name [text] x "RE": result, outcome [text] x "US": user (who entered game) [text] x "TM": time limit per player [text] x "SO": source (book, journal...) [text] x "GM": game [number] (Go=1) x "SZ": board size [number] "VW": partial view [point list] "BS": black species [number] (human=0, modem=-1, computer>0) "WS": white species [number] "EL": evaluation of computer mv [number] "EX": expected next move [move, game-specific] "SL": selected points [point list, game-specific] x "M" : marked points [point list, game-specific] x "L" : letters on points [point list, game-specific] x "BR": Black's rank [text] x "WR": White's rank [text] x "HA": handicap [number] x "KM": komi [real] "TB": Black's territory [point list] "TW": White's territory [point list] "SC": secure stones [point list] "RG": region of the board [point list] SHAR_EOF fi if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' ----------------------------------------------------------------------- "mgt" Copyright 1991 Shodan All Rights Reserved. Program by Greg Hale Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that this entire comment and copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. ----------------------------------------------------------------------- To compile under UNIX, type 'make' Under VMS, delete the mou.c file and then type '@build' Under MS-DOS with Borland-C, type 'make -f makefile.bc' For the X version (X11R4) type xmkmf && make depend && make *** Be sure to get the From My Go Teacher tutorial materials available *** on anonymous ftp at ftp.u.washington.edu. ----------------------------------------------------------------------- Please send copies of extensions to: hale@scam.berkeley.edu Thanks to the following for suggestions, debugging, code writing, and testing: mgt - you know why he's here :) Kurt Wallnau - for playing and suggesting Jeff Boscole - for sleepless nights of debugging and testing Thos Sumner - for extensive help with explaining some UNIX particulars Adrian Mariano - (adrian@u.washington.edu) - massive code extensions, plus IBM version Tim Casey (tcasey@adobe.com) X11 version. Chien-Min Wang - X11 version niceness (I mean *really* niceness). Mike Dobbins - lots of testing, suggestions and comment editor rewrite Eric Osman - for getting things to work under VMS Steve Hollasch - debugging assistance Huayong Yang - comments, bug reports -------------------------------------- Changes: 9/21/92 V2.3 o Rewrite of the comment editor; edits comments up to 120 lines long; additional and user settable edit control commands o Fixed a few parsing bugs 4/30/92 V2.2 o Increased speed of moving backwards through game record or jumping to an arbitrary node. o Tutor mode o Support for informational properties o Support for PLayer property, and passing (as a move) o Removed restriction on number of letters or marks o Detection of ko during game play o For the IBM version: Mouse support and improved display 4/5/91 V2.1 o Short format game record support o Filename wild card support o Additional comment editor features o Improved game scoring o Other? 2/1/91 V2.0 o mgt is more optimized. o IBM version support o revision of display o fixed lots of little bugs o more commands o basic editing of comments o save & load o play-by-mail facility added. 2/6/90 V1.0 o First release. All is holding together fine, but no optimization has been done yet. That is next on the list. My apologies to the CPU's. :( SHAR_EOF fi if test -f 'README.X11' then echo shar: "will not over-write existing file 'README.X11'" else cat << \SHAR_EOF > 'README.X11' ---------------------------------------------------------------------------- README FILE OF THE X11 INTERFACE FOR MGT 2.3 version 0.94 released 2.4.93 Programmed by: Chien-Min Wang, cmwang@iis.sinica.edu.tw Tim Casey, tcasey@adobe.com This program is distributed in the hope that it will be useful. Use and copying of this software and preparation of derivative works based upon this software are permitted, so long as the following conditions are met: o credit to the authors is acknowledged o no fees or compensation are charged for use, copies, or access to this software o this copyright notice is included intact. This software is made available AS IS, and no warranty is made about the software or its performance. Bug descriptions, use reports, comments or suggestions are welcome. Send them to cmwang@iis.sinica.edu.tw tcasey@adobe.com, yes both. ---------------------------------------------------------------------------- Thanks to the following for suggestions, code writing, and testing: Adrian Mariano - for suggestiions, and testing Stephen Coffin - for code writing (the interface to IGS uses part of his xigs program) Antoine Dumesnil de Maricourt - for code writing (the prompting box uses part of his xgoban program) Brian Totty - for code writing (the file selector uses his file selector widget) ---------------------------------------------------------------------------- Changes: Version 0.94: 1. Rearrange menu entries. 2. Correct a bug in save screen dialog box. 3. Enhance the message shown in message box. 4. Some minor correction to version 0.93. Version 0.93: 1. Some minor correction to version 0.92. Version 0.92: 1. Support of Hierarchical File Selector (HFS). 2. Some minor correction to version 0.91. Version 0.91: 1. Some minor correction to version 0.90. Version 0.90: 1. The first formal version of xmgt. 2. Support of Internet Go Server (IGS). ---------------------------------------------------------------------------- Answers to some bug reports and frequently asked questions Question: How do I build xmgt? Answer: xmkmf && make depend && make If you do not want the Hierarchical File Selector, remove the '-DXMGT_HFS' from the imakefile. The imakefile could be buggy. Please bear with us. Question: How do I build xmgt manually? Answer: make -f Makefile.1 xmgt If you can't build xmgt automatically by the above method, you may try this command to build it manually. If you do not want the Hierarchical File Selector, remove the '-DXMGT_HFS' from the file Makefile.1. Question: How to use the Hierarchical File Selector? Answer: It allows a user to move through the directory tree and select files. It has two scrolled text lists side by side. The left list contains the current directory path from the root to the current directory, listed one directory per line. The right list shows the files in the current directory. Files can be selected by clicking on the appropriate file in the right list. New files can be keyed in through the file box. Clicking on a directory will enter that directory and list its files and directories. Question: The variation window is so small, that no name of a variation will actually fit in it. Answer: Use the scroll bar at the top of the variation window to see the rest part of names. If you prefer not to use the scroll bar, you may resize the whole window horizontally to widen the variation window. Question: I can't type any characters at the promp to load a file. Similarly, I can't type any characters into the "Go to Node" prompt. Answer: You shold move the cursor to the prompt before type in any characters. Question: When I resize the screen, the board appears to be drawn twice, and the other elements of the screen are drawn several times as well. Answer: Partly corrected. The borders of board, buttons, and variations might be drawn twice, but the other elements are drawn only once. Question: When I select the load file option from the file menu, I get a prompt window. The title on the window is "pshell" and when I double click on the icon in the upper left corner of the window's border (an action which kills the window under my window server) both the prompt window, and all of xmgt are killed. If I click only once, I get a menu with options like "close". Answer: It never happened on my computer. So, it is difficult for me to figure out how it occurs. Several changes are made in the hope that the bug will be fixed. If it occurs on your computer or you know how to fix the bug, please send a mail to cmwang@iis.sinica.edu.tw. Question: I can't figure out how to use the internet go server related part. Answer: The program is not yet completed. Please do not send any bug report to the authors. If you'd like to try the program in advance, follow the following instructions. 1. Before compile the program, append '-DXMGT_IGS' to the second line of the file imakefile (for automatic compilation) or to the first line of the file Makefile.1 (for manual compilation). 2. The program must be executed in the foreground. To execute the program alone, type 'xmgt'. To execute the program in connection with IGS, type 'telnet [address] [port] | xmgt'. 3. Remember to set client mode true in IGS and to set tutor mode false in xmgt (the default is false). 4. Only one game can be observed/played at a time. Remember to type 'moves [game_no]' immediately after you type 'observe [game_no]' or 'load [game_name]'. 5. Do not modify the board when you are observeing/playing a game. 6. You can traverse the board when you are observing/playing a game. Remember to set tutor mode true before you traverse the board. To continue observing/playing, you should move to the end of variation and then set tutor mode false. SHAR_EOF fi if test -f 'RegExp.c' then echo shar: "will not over-write existing file 'RegExp.c'" else cat << \SHAR_EOF > 'RegExp.c' /**************************************************************************** RegExp.c This file contains the C code for the regular expression matching code. The routines supported act as a more friendly, user level interface to the regexp regular expression matching system. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #include "RegExp.h" /* modified by Chien-Min Wang, 1/15/93 #include <regexp.h> */ #define NO_REGEXP void RegExpCompile(regexp,fsm_ptr,fsm_length) char *regexp,*fsm_ptr; int fsm_length; { #ifndef NO_REGEXP compile(regexp,fsm_ptr,&(fsm_ptr[fsm_length]),'\0'); #endif } /* End RegExpCompile */ int RegExpMatch(string,fsm_ptr) char *string,*fsm_ptr; { #ifndef NO_REGEXP if (advance(string,fsm_ptr) != 0) return(TRUE); else return(FALSE); #else return(TRUE); #endif } /* End RegExpMatch */ void _RegExpError(val) int val; { void fprintf(); fprintf(stderr,"Regular Expression Error %d\n",val); exit(-1); } /* End _RegExpError */ void RegExpPatternToRegExp(pattern,reg_exp) char *pattern,*reg_exp; { int in_bracket; in_bracket = 0; while (*pattern != '\0') { if (in_bracket) { if (*pattern == ']') in_bracket = 0; *reg_exp++ = *pattern++; } else { switch (*pattern) { case '[': in_bracket = 1; *reg_exp++ = '['; break; case '?': *reg_exp++ = '.'; break; case '*': *reg_exp++ = '.'; *reg_exp++ = '*'; break; case '.': *reg_exp++ = '\\'; *reg_exp++ = '.'; break; default: *reg_exp++ = *pattern; break; } ++ pattern; } } *reg_exp++ = '$'; *reg_exp++ = '\0'; } /* End RegExpPatternToRegExp */ SHAR_EOF fi if test -f 'RegExp.h' then echo shar: "will not over-write existing file 'RegExp.h'" else cat << \SHAR_EOF > 'RegExp.h' /**************************************************************************** RegExp.h This file contains the C definitions and declarations for the regular expression matching code. The routines supported act as a more friendly, user level interface to the regexp regular expression matching system. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _REGEXP_H_ #define _REGEXP_H_ #include <stdio.h> #if (!NeedFunctionPrototypes) void RegExpCompile(); int RegExpMatch(); void _RegExpError(); void RegExpPatternToRegExp(); #else void RegExpCompile(char *regexp, char *fsm_ptr, int fsm_length); int RegExpMatch(char *string, char *fsm_ptr); void _RegExpError(int val); void RegExpPatternToRegExp(char *pattern, char *reg_exp); #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define INIT register char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) -- sp #define RETURN(ptr) return; #define ERROR(val) _RegExpError(val) #endif SHAR_EOF fi if test -f 'Rules' then echo shar: "will not over-write existing file 'Rules'" else cat << \SHAR_EOF > 'Rules' This files contains rules to the game of Go in Smart-Go format. It should be viewed with the mgt program. ( ; GaMe[1] VieW[] SiZe[19] Comment[ THE GAME OF GO A Brief Introduction by Adrian Mariano press . to move forward press , to move backward (in the X version make sure the sprite is over the board window.) ] ; Comment[Go is a two player strategy board game. Players take turns putting black and white pieces \(called stones\) on the board. The board is normally a 19x19 grid. The stones are placed on the intersections. Once played, a stone cannot be moved, though it may be captured by the other player. The object of the game is to surround territory.] ; Comment[There are three major scoring systems for Go: Japanese, Chinese and Ing. This tutorial describes the Japanese system, which is the most common in Western countries. Under Japanese rules, a completed game is scored as follows: each intersection surrounded and each prisoner captured count as a point. The player with the most points wins.] ; Comment[When a player has nothing left to do, he passes. After two consecutive passes, the game is over.] ; Comment[An empty intersection adjacent to a stone \(orthogonally\) is called a liberty. The white stone in the center of the board has 4 liberties, the marked spots. The white stone at the bottom has three liberties, and the white stone in corner has two liberties.] AddWhite[jj][js][ss] Mark[ij][ji][kj][jk][is][jr][ks][rs][sr] AddEmpty[aa] ; AddBlack[dc][dd][ed][fd][fe][ge] Comment[Groups of stones that are connected orthogonally can be captured all at once by removing all of their liberties. The black stones are orthogonally connected and have 11 liberties. The white stones are not orthogonally connected.] AddWhite[in][io][jn][jo][kl][km][ll][lm] Mark[ff][gf][he][gd][ee][de][cd][fc][ec][cc][db] AddEmpty[aa][ep][fp][gp][jj][jp][jq][js][kj][kk][kp][lk][lp][mp][na][np][ob][pb][pc][qd][qk][qm][rb][re][ri][rj][rk][rm][rn][ro][rp][sd][se][si][sp][ss] ; AddBlack[ij][ji][jj] AddEmpty[aa][dc][dd][ed][ep][fd][fe][fp][ge][gp][hj][in][io][jn][jo][jp][jq][kl][km][kp][ll][lm][lp][mp][na][np][ob][pb][pc][qd][qk][ql][qm][rb][re][ri][rj][rk][rm][rn][ro][rp][sd][se][si][sp] Comment[A group is captured if its last liberty is taken away. Here is a black group with seven liberties.] ; AddWhite[hj] Comment[A single white stone next to the group reduces it to six liberties.] ; AddWhite[ik][jh][jk][ki][kj] Comment[Six white stones reduces the group to one liberty \(remember that play alternates black and white. These stones could not be placed like this during a game.\)] ; White[ii] Comment[The final white move captures the black group.] ; AddWhite[qh][qi][qj][rg][rk][sg][sk] AddBlack[rh][ri][rj][sh][sj] AddEmpty[aa][hj][ii][ik][jh][jk][ki][kj] Comment[The black group has only one liberty. White can capture the black group by playing inside black at T11.] ; White[si] ; AddBlack[rh][ri][rj][sh][sj] Comment[It is illegal to comit suicide. White cannot play at T11 now, because the move does not capture the black group, and the white stone at T11 would have no liberties.] AddWhite[qh][qj][rg][rk][sg][sk] AddEmpty[aa][qi][si] ; Comment[Another rule of Go is the Ko rule. It is illegal to make a move which recreates preceeding board positions \(to prevent loops\). Suppose black captures the white stone at J12.] AddBlack[hh][ig][ii] AddWhite[ih][jg][ji][kh] AddEmpty[aa][ab][ac][aq][ar][bb][bc][bq][br][bs][ca][cb][cc][cq][cr][da][db][dc][dq][dr][ds][eq][er][es][qg][qh][qi][qj][qk][ql][rf][rg][rh][ri][rj][rk][rl][sf][sg][sh][sj][sk][sl] ; Black[jh] Comment[If white were allowed to play at J12 now, the board would look exactly as it did before.] ; AddEmpty[jh] AddWhite[ih] Comment[This white move is ILLEGAL. White must wait a turn before making this move, giving black the option of filling in the hole at J12.] ; AddEmpty[aa][hh][ig][ih][ii][jg][ji][kh][ph][qh][qj][rg][rh][ri][rj][rk][sg][sh][sj][sk] Comment[The concept of life is an important, and tricky one. You must know how to make a living group. A living group is one that can't be captured. A liberty which is inside a group and completely surrounded is called an eye. A group with two disconnected eyes cannot be captured.] ; AddBlack[ic][id][ie][jc][je][jj][jk][jl][kc][kd][ke][kj][kl][lc][le][lj][lk][ll][mc][md][me] AddWhite[hc][hd][he][ib][if][ij][ik][il][jb][jf][ji][jm][kb][kf][ki][km][lb][lf][li][lm][mb][mf][mj][mk][ml][nc][nd][ne] AddEmpty[aa][hb][hf][ii][im][mi][mm][nb][nf] Comment[The black group above cannot be captured, because it has two eyes, the points K16 and M16. White cannot play in either eye, because his stone would have no liberties. White CAN capture the lower group, however, because it has only a single eye, and a white stone played within it reduces black to zero liberties.] ; White[kk] ; AddWhite[aq][ar][bq][bs][cq][cr][cs] AddBlack[ap][bp][cp][dp][dq][dr][ds] AddEmpty[aa][hc][hd][he][ib][ic][id][ie][if][ij][ik][il][jb][jc][je][jf][ji][jm][kb][kc][kd][ke][kf][ki][kk][km][lb][lc][le][lf][li][lm][mb][mc][md][me][mf][mj][mk][ml][nc][nd][ne] Comment[Here is another example of a living group. Black cannot capture the white group, because it has two eyes at A1 and B2. Black cannot play at either of these points, because the black stone would have no liberties.] ; Comment[The black group here has only ONE eye. If black does not make further moves in this area, white can capture black. \(More on this shape later.\)] AddBlack[ap][bp][cp][cq][cr][cs] AddWhite[ao][bo][co][do][dp][dq][dr][ds] AddEmpty[aa][aq][ar][bq][br][bs] ; AddBlack[ao][bo][co][do][eo][fo][go][ho][hp][hq][hr][hs] AddWhite[ap][bp][cp][cr][dp][dq][dr][ds][ep][fp][gp][gq][gr][gs] Comment[The white group here is also alive. If black plays inside, white can safely ignore his plays completely. White will be able to capture the black stones no matter what black does. If black does this, white can gain points by simply passing. ] AddEmpty[aa][cq][cs] ; AddBlack[af][al][bf][bg][bk][bl][cg][ch][ci][cj][ck][ga][gb][gc][hc][ic][jc][kc][lc][ma][mb][mc] AddWhite[ag][ai][ak][bh][bi][bj][ha][hb][ib][ja][jb][kb][la][lb] AddEmpty[aa][ao][ap][bo][bp][co][cp][cr][do][dp][dq][dr][ds][eo][ep][fo][fp][go][gp][gq][gr][gs][ho][hp][hq][hr][hs] Comment[Compare these two white groups. The white group at the top is alive, because it has two eyes. But beware! The white group on the left side is dead!] ; Comment[The Ko rules prevents white from recapturing the stone at A12. White must play somewhere else on the board, allowing black to capture the stones.] Black[ah] ; Black[aj] ; Comment[Here is another example of a DEAD group. The white group at the bottom does NOT have two eyes.] AddBlack[lp][lq][lr][ls][mp][np][op][oq][or][pp][qp][rp][sp][sq][sr] AddWhite[mr][ms][nr][os][pq][pr][ps][qq][rq][rr][rs] AddEmpty[aa][af][ah][aj][al][bf][bg][bk][bl][cg][ch][ci][cj][ck][ga][gb][gc][ha][hb][hc][ib][ic][ja][jb][jc][kb][kc][la][lb][lc][ma][mb][mc][mq][nq] ; AddWhite[ar][br][cr][cs] AddBlack[aq][bq][cq][dq][dr][ds] AddEmpty[aa][ao][ap][bo][bp][co][cp][do][dp][eo][ep][fo][fp][go][gp][gq][gr][gs][ho][hp][hq][hr][hs][lp][lq][lr][ls][mp][mr][ms][np][nr][op][oq][or][os][pp][pq][pr][ps][qp][qq][rp][rq][rr][rs][sp][sq][sr] Comment[In this example, the white group is dead. There is nothing white can do to prevent black from capturing it.] ; Black[bs] ; White[as] ; Black[bs] Comment[Notice that black had to sacrifice a stone to capture the white group, but black succeeds in the end. Because both players can tell that black will be able to capture white, black does not actually need to play any stones. This group is dead and will be removed at the end of the game.] ; AddWhite[ar][br][cr][dr][ds] AddBlack[eq][er][es] AddEmpty[aa][bs] Comment[This case is more complicated. If white plays first, then the group has two eyes and lives.] ; White[bs] ; Comment[On the other hand, if black plays first, the group is killed. ] AddEmpty[aa][bs] ; Black[bs] ; White[cs] ; Black[as] ; Comment[In this case, the white group is alive, even if black plays first.] AddWhite[ar][br][cr][dr][er][es] AddBlack[aq][fq][fr][fs] AddEmpty[aa][as][bs][en] ; Black[cs] ; White[bs] ; Comment[In this case, however, the white stones can be killed if black moves first. \(If white plays first at B1, then they are alive.\)] AddBlack[ap][bp][cp][dp][dq][eq][er][es] AddWhite[aq][bq][cq][cr][ds] AddEmpty[aa][ar][bn][br][bs][cs] ; Black[bs] ; White[br] ; Black[as] ; White[cs] ; Black[ar] ; AddWhite[ao][bo][co][do][dp][dq][dr][ds] AddBlack[ap][bp][cp][cq][cr][cs] AddEmpty[aa][aq][ar][as][bq][bs][eq][er][es][fq][fr][fs] Comment[As promised, here is the situation we saw earlier. This situation is similar to the preceeding one. If black plays first, then black can live.] ; Black[br] ; White[ar] ; Black[aq] ; White[bs] ; Black[as] ; AddEmpty[aa][aq][ar][as][br][es] Comment[If, however, white plays first, white can kill the black group.] ; White[br] ; Black[bs] ; White[ar] ; Black[aq] ; White[as] ; Black[bq] ; White[ar] ; Black[br] ; White[as] ; AddWhite[ab][ai][am][ar][bb][bi][bm][br][ca][cb][ci][cj][ck][cl][cm][cr][dr][ds][rh][ri][rj][rk][sg][si][sk] AddBlack[ac][ah][ak][an][aq][bc][bh][bk][bn][bq][bs][cc][ch][cn][cq][da][db][dc][dh][di][dj][dk][dl][dm][dn][dq][eq][er][es][qg][qh][qi][qj][qk][ql][rf][rg][rl][sf][sl] AddEmpty[aa][ao][as][bo][co][do][dp][sh] Comment[Each of these groups is dead. In all cases where a group can be considered dead, it can be removed from the board at the end of the game without further play. It is NOT advantageous to capture groups which are dead, unless they threaten your position, because doing so reduces your own territory, and may allow your opponent to make important moves.] ; AddBlack[cj][ck][cl][cm][cn][co][db][dc][dd][de][df][dg][dj][do][ea][eb][eg][ej][eo][fa][fg][fj][fo][ga][gg][gj][gn][go][ha][hg][hj][hn][ia][ib][if][ig][ij][ik][il][im][in][jb][jc][jd][je][jf][jg][km][kn][ko][kp][kq][ll][lm][lq][lr][ml][mr][nl][nr][ol][or][pd][pe][pf][pg][ph][pl][pm][pq][pr][qc][qd][qh][qi][qm][qn][qo][qp][qq][rc][ri][sc][si] AddWhite[dk][dl][dm][dn][ec][ed][ee][ef][ek][en][fb][fc][ff][fk][fn][gb][gf][gk][gm][hb][hc][he][hf][hk][hl][hm][ic][id][ie][ln][lo][lp][mm][mn][mp][mq][nm][nq][om][on][op][oq][pn][po][pp][qe][qf][qg][rd][re][rg][rh][sd][sh] Comment[All of the white groups are dead if black moves first, but live if white moves first. Can you find the move that kills each group?] AddEmpty[aa][ab][ac][ah][ai][ak][al][am][an][aq][ar][bb][bc][bd][be][bh][bi][bk][bl][bm][bn][bq][br][bs][ca][cb][cc][ch][ci][cq][cr][da][dh][di][dq][dr][ds][eh][ei][el][eq][er][es][fh][fl][gh][gl][hh][ih][ii][jh][ji][jj][jk][kh][qj][qk][ql][rf][rj][rk][rl][sf][sg][sk][sl] ; AddEmpty[aa][cj][ck][cl][cm][cn][co][db][dc][dd][de][df][dg][dj][dk][dl][dm][dn][do][ea][eb][ec][ed][ee][ef][eg][ej][ek][en][eo][fa][fb][fc][ff][fg][fj][fk][fn][fo][ga][gb][gf][gg][gj][gk][gm][gn][go][ha][hb][hc][he][hf][hg][hj][hk][hl][hm][hn][ia][ib][ic][id][ie][if][ig][ij][ik][il][im][in][jb][jc][jd][je][jf][jg][km][kn][ko][kp][kq][ll][lm][ln][lo][lp][lq][lr][ml][mm][mn][mp][mq][mr][nl][nm][nq][nr][ol][om][on][op][oq][or][pd][pe][pf][pg][ph][pl][pm][pn][po][pp][pq][pr][qc][qd][qe][qf][qg][qh][qi][qm][qn][qo][qp][qq][rc][rd][re][rg][rh][ri][sc][sd][sh][si] Comment[If there is debate over who owns a territory, or whether a group is alive, simply continue play until the players agree.] ; AddBlack[an][ap][bn][bo][bp][br][bs][cp][cs][dp][ds][ep][er][es][fp][gp][gq][gr][gs][hr][ir][is] AddWhite[aq][ar][as][bq][cq][dq][eq][fq][fr][fs] AddEmpty[ai][aj][ak][al][am][bi][bj][bk][bl][bm][cr][dr] Comment[This situation is called seki. Even though the white group and the black group contained inside do not have two eyes, they are considered alive. The reason is that neither black nor white can make a move in the region. ] ( ; White[cr] Comment[If white attempts to capture black by playing inside...] ; Black[dr] Comment[Then black captures the white stones.] ) ( ; Comment[If black tries to capture white by moving inside...] Black[cr] ; Comment[Then white captures black, and now the white group is alive. ] White[dr] ; Comment[Notice that the black group around the very outside is clearly alive, with two eyes. If white were able to surround and capture the black group, then he could break the deadlock and the situation would no longer be seki.] ; AddEmpty[aa][an][ap][aq][ar][as][bo][bp][bq][cp][cq][dp][dq][dr][ep][eq][fp][fq][fr][fs][gp][gq][gr][gs][hr][ir][is] Comment[Examine this situation. The white and black groups have started surrounding each other. This is called a "capture race." If white plays first, who will capture whom?] AddWhite[bh][bi][bj][bn][cj][cm][cn][dk][dl] AddBlack[bf][bk][bl][bm][cf][cg][ch][ci][ck][di][dj] ; White[am] ; Black[bg] ; White[al] ; Black[ah] ; White[ak] ; Black[ai] ; White[cl] ; Black[ag] ; White[aj] ; Comment[Connections of stones are very important. If two groups each have one eye, they can live if they can be connected directly to each other.] AddEmpty[aa][ag][ah][ai][aj][ak][al][am][bf][bg][bh][bi][bj][bn][cf][cg][ch][ci][cj][cl][cm][cn][di][dj][dk][dl] AddBlack[aq][bq][cq][cr][dq][eq][fq][gq][gr][gs] AddWhite[ar][br][bs][dr][ds][er][fr][fs] ( ; Black[cs] Comment[If black plays here, then the two white groups will die, since each has only one eye.] ) ( ; White[cs] Comment[If white plays C1, then his stones are connected into one group which has two eyes.] ; AddEmpty[aa][aq][ar][bq][br][bs][cq][cr][cs][dq][dr][ds][eq][er][fq][fr][fs][gq][gr][gs] Comment[Obviously, this sort of loose connection only works if it happens to be white's turn. It is not reasonable to play all your stones solidly connected, because you will not be able to get much territory. You must instead make different types of connections which can be fortified when they are attacked.] ; Comment[In this situation, the black stones can be considered connected, even though they are not yet orthogonally connected directly.] AddWhite[ah][al][bh][bl][ch][ci][ck][cl][di][dk][dl][ei][el][fi][fl][gi][gj][gl][gm][hi][hm][ii][im][ji][jm][ki][kj][kk][kl][km] AddBlack[ai][ak][bi][bj][bk][cj][dj][ej][fk][gk][hj][hk][hl][ij][il][jj][jk][jl] AddEmpty[aa][cs][ek][fj][lj][lk][ll][mj][mk][ml][nj][nk][nl][oj][ok][ol][pj][pk][pl][qi][qj][qk][ql][qm][ri][rj][rk][rl][rm][si][sj][sl][sm] ; Comment[If white threatens to disconnect the black stones...] White[fj] ; Comment[...black always has a response which connects his stones. ] Black[ek] ; AddBlack[lm][lp][mm][mp][nm][np] Comment[Here is another strong connection that cannot be cut.] AddWhite[io][jo][ko][ln][lo][nn][no][on][pn][qn] AddEmpty[aa][ah][ai][ak][al][bh][bi][bj][bk][bl][ch][ci][cj][ck][cl][di][dj][dk][dl][ei][ej][ek][el][fi][fj][fk][fl][gi][gj][gk][gl][gm][hi][hj][hk][hl][hm][ii][ij][il][im][jc][jd][je][ji][jj][jk][jl][jm][kc][ke][ki][kj][kk][kl][km][lc][ld][le][md][nd][ne][pa][pb][pc][pd][pe][qa][qb][qc][qd][ra][rb][rc][rd][sb][sc] ; Comment[If black tries to disconnect the white stones...] Black[mo] ; Comment[...as with the diagonal connection, white always has a response which directly connects his stones. \(This is called a bamboo connection\)] White[mn] ; Comment[There are several other weaker connections which can be cut. ] AddEmpty[aa][ao][aq][bn][bo][bp][bq][br][cn][cp][cr][dm][dn][do][dp][dq][dr][ep][eq][fo][fp][fq][gp][gq][hp][io][ip][jo][jp][ko][kp][kq][lm][ln][lo][lp][lq][mm][mn][mo][mp][mq][nm][nn][no][np][on][pn][qn] ; Comment[These are all weaker connections. Whether the stones can be separated depends on the location on the board and what other stones are in place. The marked locations are the cutting points -- the moves white would make to disconnect black.] Mark[fo][fb][fe][gh][fk] AddEmpty[aa][cl][cp][dl][dp][ec][ej][el][ep][fc][fi][fj][fo][fp][gi][gj][gp][hd][hi][hm][id][ii][ij][im][jd][jj][jm][kd][kj][kp][lp][pg][ph][pi][ql][qm][qn] AddBlack[cb][ce][ch][ck][co][db][de][dh][dk][do][eb][ee][eh][ek][eo][gb][gl][hb][he][hl][hp][ib][ie][ih][il][ip][je][jh][jp][kh] ; Comment[In previous diagrams, several times a ko has arisen during an attempt to capture a group. In these cases, I have ignored the possible reprecussions of the play that must be made elsewhere. Now consider this one situation on the whole board. White wishes to kill the black group at the left.] AddBlack[bp][cp][dp][dq][dr][ph][pm][pn][po][pp][pq][qi][qq][qr][qs][ri][rj][rk][rs][si][sl] AddWhite[bm][bo][co][do][eo][ep][eq][er][gr][oj][ok][ol][pl][ql][qn][rl][rn][ro][rp][rq][sq] AddEmpty[aa][cb][ce][ch][ck][co][db][de][dh][dk][do][eb][ee][eh][ek][eo][gb][gl][hb][he][hl][hp][ib][ie][ih][il][ip][je][jh][jp][kh] ; White[br] ; Black[ar] ; White[cr] ; Black[ds] ; White[ap] ; Black[aq] ; White[ao] ; Black[bq] ; White[cs] ; Black[bs] ; Comment[We have reached a Ko situation. Black may not retake the white stone at A1. Black may, however, attack the white formation on the right side of the board.] White[as] ; Comment[This attack by black is called a "ko threat." Black is forcing white to decide between killing the group in the left corner, and connecting on the right. Note that if white does not connect on the right, then the white stones on the right will die.] Black[qm] ( ; Name[On the right] Comment[White will now respond on the right, connecting the white groups together.] White[rm] ; Black[bs] ; Comment[White cannot retake the ko at B1 now. He would like to find an attack similar to the one black used on him, but since the board is almost empty, no such attack exists. \(White can play at T7, threatening to capture the single black stone, but black would much rather save his 10 corner stones than a single side stone.\)] White[sm] ; Black[cq] Comment[The black group lives.] ) ( ; Comment[White plays in the corner, planning to kill the group on the left.] Name[In the corner] ; White[bs] ; Black[cq] ; Comment[The black stones are dead.] White[bs] ; Comment[But black gets to cut off the white stones.] Black[rm] ; Comment[Suppose black wants to capture the white stone. ] AddBlack[dm][em][fn] AddWhite[en] AddEmpty[aa][ao][ap][aq][ar][as][bm][bo][bp][bq][br][bs][cn][co][cp][cq][cs][dn][do][dp][dq][dr][ds][eo][ep][eq][er][es][gr][oj][ok][ol][ph][pl][pm][pn][po][pp][pq][qi][ql][qm][qn][qq][qr][qs][ri][rj][rk][rl][rm][rn][ro][rp][rq][rs][si][sl][sq] ( ; Comment[If black plays here...] Black[dn] ; Comment[...white escapes downward. This is not the correct approach.] White[eo] ) ( ; Comment[Instead, black should play here. This starts a pattern called the "ladder," a very common occurrence in go games.] Black[eo] ; Comment[The only direction white can go is leftwards. However, observe the sequence that follows. ] White[dn] ; Black[cn] ; White[do] ; Black[dp] ; White[co] ; Black[bo] ; White[cp] ; Black[cq] ; White[bp] ; Black[ap] ; White[bq] ; Black[br] ; White[aq] ; Comment[Each of the moves is forced, and white is unable to save the stones. White must be able to recognize this, so he can avoid playing this sequence and losing such a large group of stones.] Black[ar] ; Comment[The outcome is very different if white has a stone in the path of the ladder.] AddBlack[fn] AddWhite[bo][en] AddEmpty[aa][ap][ar][br][cn][co][cq][dn][dp][eo] ; Black[eo] ; White[dn] ; Black[cn] ; White[do] ; Black[dp] ; White[co] ; Black[cm] ; White[ep] ; Black[fo] ; Comment[Black fails to capture white in this case.] White[dq] ; Comment[In this case, white wishes to capture the black stone. ] AddWhite[jh][ji][jj][kj][lj] AddBlack[ki] AddEmpty[aa][bo][cm][cn][co][dm][dn][do][dp][dq][em][en][eo][ep][fn][fo][iq] ; Comment[To do so, white plays here.] White[lh] ; Black[li] ; White[mi] ; Black[kh] ; White[kg] ; AddEmpty[aa][jh][ji][jj][kg][kj][lh][lj][mi] Comment[It is important to remember that the object of the game is TERRITORY, not captured stones. Capturing stones, or preventing stones from being captured is important only when it increases your territory. A frequent beginner error is to place too much emphasis on capturing stones.] ; AddBlack[ap][bp][cp][da][db][dc][dd][dp][dq][dr][ds][ed][fd][gd][ha][hb][hc][hd][ih][ii][ij][ik][il][jh][jl][kh][kl][lh][ll][mh][mi][mj][mk][ml] Comment[It is easiest to make territory in the corner, and hardest in the center. Each group surrounds nine points of territory. The corner group is 7 stones, side group is 11 stones, and the center is 16 stones. Because of this, you should start in the corner, and expand along the sides from the corners, and finally expand into the center from the sides.] ; AddEmpty[aa][ap][bp][cp][da][db][dc][dd][dp][dq][dr][ds][ed][fd][gd][ha][hb][hc][hd][ih][ii][ij][ik][il][jh][jl][kh][kl][lh][ll][mh][mi][mj][mk][ml] Comment[A common opening move is to play at the 4,4 point in one of the corners. This move has potential to claim corner territory, side territory, and even center territory.] Black[pp] ; White[qq] Comment[Note that white can play underneath black and take the corner despite the black stone at the 4,4 point, however. This move by white is NOT an opening move, but is an attack that would occur later in the game.] ; AddBlack[qq] AddEmpty[aa][pp] Comment[Opening at the 3,3 point insures ownership of the corner but has less potential for extension into the center.] ; AddBlack[de][pq] AddEmpty[aa][qq] Comment[Other good openings are the 5,4 point and the 3,4 point.] ; Comment[From either of these openings, black can make a corner enclosure so get corner territory.] AddBlack[dc][qo] ; Comment[And then extend along the side, staking out side territory.] AddBlack[ic][kq] ; AddEmpty[dc][de][ic][kq][pq][qo] AddBlack[dd][dj][dp][jj][pd][pj][pp] Comment[Go players use a handicap system to balance games between players of different skill. The weaker player starts by placing from two to nine stones on the board in a special configuration on the handicap points. This is a seven stone handicap.] ; AddEmpty[aa][dd][dj][dp][jj][pd][pj][pp] Comment[Playing strength of amateurs is measured on a scale where one unit corresponds to a handicap stone. A total beginner is 35 kyu, and will very quickly improve to 20 kyu. A player will reach 10 kyu after playing about 100 games. Ranks worse than 10 kyu are unreliable because playing is too uneven and players progress too quickly to get a stable rating.] ; Comment[Beyond the kyu ranks are the amateur dan ranks which go from 1 dan to 6 dan, the highest amateur rank. A 5 kyu player would give a 9 kyu player a four stone handicap. A 2 dan player would give a two stone handicap to a 1 kyu player. Each handicap stone is worth about 10 points.] ; Comment[Professional players have a different ranking system from 1 dan \(lowest\) to 9 dan \(highest\) which has a finer grating: a 9 dan is about two stones better than a 1 dan. ] ; Comment[Playing Black, who always moves first, is advantageous because you start with the initiative. Generally, white is given 5.5 extra points, called a komi, to compensate for his disadvantage. \(The 1/2 point prevents tie games.\)] ; Comment[A new player should begin by playing several games on a 9x9 board, followed by several games on a 13x13 board before finally playing on the full sized 19x19 board.] ; Comment[The strategy of go is very complex and intricate. If you wish to become a good player, you should buy a book about the game. Computer go programs are presently very weak -- they are ranked around 10 kyu] ) ) ) ) ) SHAR_EOF fi if test -f 'Sample.01' then echo shar: "will not over-write existing file 'Sample.01'" else cat << \SHAR_EOF > 'Sample.01' ( ; GaMe[1] VieW[] SiZe[19] Comment[A game between two amateurs both ranked betwen 10 kyu and 15 kyu Result: with no komi, black wins by 4] ; Black[pd] ; White[qp] ; Black[dp] ; White[dc] ; Black[op] ; White[po] ; Black[lp] ; White[pl] ; Black[de] ; White[cd] ; Black[ed] ; White[ce] ; Black[cf] ; White[ec] ; Black[ci] ; White[fd] ; Black[fe] ; White[gd] ; Black[ph] ; White[qi] ; Black[nc] ; White[cn] ; Black[dn] ; White[cp] ; Black[co] ; White[bo] ; Black[do] ; White[dq] ; Black[bp] ; White[bq] ; Black[ap] ; White[cq] ; Black[bn] ; White[ep] ; Black[eo] ; White[fq] ; Black[fp] ; White[eq] ; Black[gp] ; White[gq] ; Black[hq] ; White[hp] ; Black[ho] ; White[iq] ; Black[ip] ; White[hr] ; Black[jq] ; White[ir] ; Black[jr] ; White[go] ; Black[gn] ; White[io] ; Black[hn] ; White[hp] ; Black[fo] ; White[jp] ; Black[kq] ; White[jn] ; Black[kd] ; White[jc] ; Black[kc] ; White[jd] ; Black[lg] ; White[ke] ; Black[le] ; White[kf] ; Black[lf] ; White[if] ; Black[gg] ; White[ge] ; Black[ff] ; White[jh] ; Black[hj] ; White[jk] ; Black[mk] ; White[pq] ; Black[oq] ; White[qh] ; Black[qg] ; White[pi] ; Black[oh] ; White[oi] ; Black[ni] ; White[nh] ; Black[ng] ; White[nj] ; Black[mh] ; White[mj] ; Black[lm] ; White[kp] ; Black[lo] ; White[lq] ; Black[lr] ; White[js] ; Black[mq] ; White[oo] ; Black[no] ; White[nn] ; Black[nm] ; White[mn] ; Black[lj] ; White[mi] ; Black[li] ; White[mo] ; Black[np] ; White[nk] ; Black[ml] ; White[nl] ; Black[mm] ; White[om] ; Black[il] ; White[hh] ; Black[gh] ; White[gf] ; Black[kg] ; White[jg] ; Black[ii] ; White[bf] ; Black[df] ; White[cg] ; Black[dg] ; White[bh] ; Black[ch] ; White[bg] ; Black[bi] ; White[gi] ; Black[hi] ; White[dd] ; Black[ee] ; White[hg] ; Black[fg] ; White[ji] ; Black[gj] ; White[nh] ; Black[pg] ; White[aq] ; Black[ao] ; White[jl] ; Black[kl] ; White[im] ; Black[hl] ; White[ln] ; Black[pr] ; White[qr] ; Black[ps] ; White[qs] ; Black[or] ; White[km] ; Black[ko] ; White[lk] ; Black[kk] ; White[ll] ; Black[kj] ; White[jj] ; Black[jo] ; White[rg] ; Black[rf] ; White[rh] ; Black[ip] ; White[hq] ; Black[in] ; White[kn] ; Black[hm] ; White[kb] ; Black[lb] ; White[ka] ; Black[la] ; White[jb] ; Black[lc] ; White[ih] ; Black[ah] ; White[ag] ; Black[ai] ; White[be] ; Black[sg] ; White[sh] ; Black[ks] ; White[is] ; Black[ik] ; White[kh] ; Black[lh] ; White[jm] ; Black[sf] ; White[ni] ; Black[pp] ; White[qq] ) SHAR_EOF fi if test -f 'Sample.02' then echo shar: "will not over-write existing file 'Sample.02'" else cat << \SHAR_EOF > 'Sample.02' ( ; GaMe[1] SiZe[19] VieW[] Comment[16th Honinbo League Playoff White: Sakata Eio 9-dan Black: Kitani Minoru 9-dan Komi: 4 1/2 Result: White wins by 3 1/2 points] Black[qd] ; White[dc] ; Black[pq] ; White[cq] ; Black[oc] ; White[po] ; Black[qo] ; White[qn] ; Black[qp] ; White[pm] ; Black[nq] ; White[qi] ; Black[ce] ; White[dh] ; Black[ee] ; White[cb] ; Black[cc] ; White[gc] ; Black[bc] ; White[bb] ; Black[qg] ; White[dd] ; Black[de] ; White[cg] ; Black[co] ; White[cm] ; Black[ep] ; White[do] ; Black[dp] ; White[cp] ; Black[dn] ; White[bo] ; Black[eo] ; White[cn] ; Black[el] ; White[dk] ; Black[ql] ; White[rm] ; Black[rj] ; White[qe] Comment[Complications start. Creating two weak groups. ] ; Black[qj] ; White[rd] ; Black[qc] ; White[qf] ; Black[pg] ; White[rc] ; Black[rb] ; White[oe] ; Black[mc] ; White[op] ; Black[on] ; White[pn] ; Black[oq] ; White[mo] ; Black[mp] Comment[Severe attack. ] ; White[lo] Comment[Counters aggressively. ] ; Black[no] ; White[np] ; Black[nm] Comment[Black cuts. Brings on crisis.] ; White[pj] ; Black[pi] ; White[pk] ; Black[rl] ; White[ml] ; Black[nl] ; White[nk] ; Black[mk] ; White[om] Comment[Exquisite shinogi tesuji. Lets W secure his endangered group] ; Black[nj] ; White[ok] ; Black[ll] ; White[lp] ; Black[mq] ; White[mn] ; Black[mm] ; White[nn] ; Black[rf] Comment[Turns toward other weak group. ] ; White[re] ; Black[rg] ; White[nd] ; Black[nc] ; White[nf] ; Black[nh] ; White[lf] ; Black[le] ; White[mh] ; Black[mi] ; White[me] ; Black[mg] ; White[ld] ; Black[ke] ; White[md] ; Black[kb] ; White[kc] ; Black[jb] ; White[id] ; Black[kf] ; White[oi] ; Black[ph] ; White[jc] Comment[Manages to rescue weak group. ] ; Black[ib] ; White[fd] ; Black[eg] ; White[lg] Comment[Double attack.] ; Black[lh] ; White[kg] ; Black[if] ; White[hg] ; Black[hf] ; White[gf] ; Black[ge] ; White[fe] ; Black[jg] ; White[he] Comment[First time that B is the one under pressure.] ; Black[gg] ; White[ff] ; Black[dg] ; White[ef] ; Black[df] ; White[fg] ; Black[ch] ; White[bh] ; Black[ci] ; White[bf] ; Black[ei] ; White[cj] ; Black[gh] ; White[fh] ; Black[eh] ; White[dj] ; Black[di] ; White[bi] ; Black[fi] ; White[gi] ; Black[gj] ; White[hh] ; Black[ii] ; White[mf] ; Black[jh] Comment[Fight ends. ] ; White[er] Comment[W has taken the lead.] ; Black[fk] ; White[ro] ; Black[rp] ; White[fq] ; Black[in] ; White[go] ; Black[gn] ; White[jn] ; Black[jm] ; White[fn] ; Black[hn] ; White[fo] ; Black[en] ; White[fm] ; Black[dl] ; White[cl] ; Black[hl] ; White[km] ; Black[jl] ; White[lq] ; Black[ip] ; White[lr] ; Black[hq] ; White[os] ; Black[or] ; White[gq] ; Black[dq] ; White[dr] ; Black[be] ; White[hb] ; Black[ic] ; White[sb] ; Black[ra] ; White[ie] ; Black[hc] ; White[gb] ; Black[gr] ; White[hi] ; Black[hj] ; White[ns] ; Black[ps] ; White[mr] ; Black[pp] ; White[oo] ; Black[rr] ; White[ej] ; Black[fj] ; White[ir] ; Black[hr] ; White[jr] ; Black[jo] ; White[kn] ; Black[ab] ; White[qk] ; Black[rk] ; White[oj] ; Black[ia] ; White[jp] ; Black[fr] ; White[iq] ; Black[hp] ; White[eq] ; Black[af] ; White[kl] ; Black[kk] ; White[ko] ; Black[ag] ; White[kh] ; Black[ki] ; White[bg] ; Black[gm] ; White[ng] ; Black[mh] ; White[sl] ; Black[so] ; White[rn] ; Black[hd] ; White[gd] ; Black[lm] ; White[ri] ; Black[si] ; White[sf] ; Black[sg] ; White[io] ; Black[ho] ; White[cd] ; Black[bd] ; White[pd] ; Black[pc] ; White[se] ; Black[nr] ; White[ms] ; Black[ha] ; White[ga] ; Black[lc] ; White[kd] ; Black[ed] ; White[ec] ; Black[fl] ; White[ah] ; Black[ae] ; White[je] ; Black[jf] ; White[ni] ; Black[mj] ; White[ih] ; Black[sc] ; White[sd] ; Black[od] ; White[pf] ; Black[db] ; White[eb] ; Black[ba] ; White[da] ; Black[do] ; White[hs] ; Black[og] ; White[of] ; Black[es] ; White[ds] ; Black[fs] ; White[jo] ; Black[ac] ; White[pe] ) SHAR_EOF fi if test -f 'ScrList.c' then echo shar: "will not over-write existing file 'ScrList.c'" else cat << \SHAR_EOF > 'ScrList.c' /***************************************************************************** ScrolledList.c This file contains the C code for the ScrolledList widget, which acts as a vertically scrolling list of text, from which, items can be selected. ******************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #include <stdio.h> #include <X11/Xos.h> #include <X11/Xlib.h> #include <X11/StringDefs.h> #include <X11/IntrinsicP.h> #include <X11/Intrinsic.h> #include <X11/CompositeP.h> #include <X11/Composite.h> #include <X11/Xaw/ViewportP.h> #include <X11/Xaw/Viewport.h> #include "MultiListP.h" #include "MultiList.h" #include "ScrListP.h" #include "ScrList.h" /*---------------------------------------------------------------------------* D E C L A R A T I O N S *---------------------------------------------------------------------------*/ #define SUPERCLASS (&compositeClassRec) #define max(a,b) ((a) > (b) ? (a) : (b)) #define min(a,b) ((a) < (b) ? (a) : (b)) #define abs(a) ((a) < 0 ? -(a) : (a)) #define XtStrlen(s) ((s) ? strlen(s) : 0) #define offset(field) XtOffset(XfwfScrolledListWidget, \ scrolledList.field) #define coffset(field) XtOffset(Widget,core.field) #define MyData(w) ((w)->scrolledList) #define CoreData(w) ((w)->core) #if (!NeedFunctionPrototypes) static void MultiListCallbackHandler(); static void ClassInitialize(); static void Initialize(); static void Realize(); static void Destroy(); static void Resize(); static Boolean SetValues(); static XtGeometryResult GeometryManager(); static XtGeometryResult PreferredGeometry(); static void ReCalcChildren(); #else static void MultiListCallbackHandler(Widget w, Widget self, XfwfMultiListReturnStruct *call_data); static void ClassInitialize(void); static void Initialize(Widget request, Widget new); static void Realize(Widget gw, XtValueMask *valueMask, XSetWindowAttributes *attrs); static void Destroy(Widget gw); static void Resize(Widget gw); static Boolean SetValues(Widget gcurrent, Widget grequest, Widget gnew); static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply); static XtGeometryResult PreferredGeometry(XfwfScrolledListWidget slw, XtWidgetGeometry *parent_idea, XtWidgetGeometry *our_idea); static void ReCalcChildren(XfwfScrolledListWidget w); #endif /*---------------------------------------------------------------------------* R E S O U R C E I N I T I A L I Z A T I O N *---------------------------------------------------------------------------*/ static XtResource resources[] = { {XtNwidth,XtCWidth,XtRDimension,sizeof(Dimension), coffset(width),XtRString,"200"}, {XtNheight,XtCHeight,XtRDimension,sizeof(Dimension), coffset(height),XtRString,"500"}, {XtNbackground,XtCBackground,XtRPixel,sizeof(Pixel), coffset(background_pixel),XtRString,"white"}, {XtNlist,XtCList,XtRPointer,sizeof(char **), offset(item_array),XtRPointer,NULL}, {XtNnumberStrings,XtCNumberStrings,XtRInt,sizeof(int), offset(item_count),XtRInt,0}, {XtNsensitiveArray,XtCList,XtRPointer,sizeof(Boolean *), offset(sensitive_array),XtRPointer,NULL}, {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), offset(callback), XtRCallback, NULL} }; #undef offset #undef coffset /*---------------------------------------------------------------------------* C L A S S A L L O C A T I O N *---------------------------------------------------------------------------*/ XfwfScrolledListClassRec xfwfScrolledListClassRec = { { /* superclass */ (WidgetClass)SUPERCLASS, /* class_name */ "XfwfScrolledList", /* widget_size */ sizeof(XfwfScrolledListRec), /* class_initialize */ (XtProc)ClassInitialize, /* class_part_initialize*/ NULL, /* class_inited */ FALSE, /* initialize */ (XtInitProc)Initialize, /* initialize_hook */ NULL, /* realize */ (XtRealizeProc)Realize, /* actions */ NULL, /* num_actions */ 0, /* resources */ resources, /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ (XtWidgetProc)Destroy, /* resize */ (XtWidgetProc)Resize, /* expose */ NULL, /* set_values */ (XtSetValuesFunc)SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ NULL, /* query_geometry */ (XtGeometryHandler) PreferredGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, /* Core Part */ { /* geometry_manager */ GeometryManager, /* change_managed */ XtInheritChangeManaged, /* insert_child */ XtInheritInsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ NULL }, /* Composite Part */ { /* no extra class data */ 0 } /* XfwfScrolledList Part */ }; WidgetClass xfwfScrolledListWidgetClass = (WidgetClass)&xfwfScrolledListClassRec; /*---------------------------------------------------------------------------* E X P O R T E D M E T H O D S *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------* MultiListCallbackHandler(w,client_data,call_data) This routine gets called when the user clicks on a MultiList item. It in turn calls any callbacks in the ScrolledList widget. *---------------------------------------------------------------*/ static void MultiListCallbackHandler(w,self,call_data) Widget w; Widget self; XfwfMultiListReturnStruct *call_data; { Boolean highlighted,sensitive; XfwfScrolledListReturnStruct ret_value; if (call_data->num_selected) { ret_value.index = call_data->selected_items[0]; XfwfMultiListGetItemInfo((XfwfMultiListWidget)w, ret_value.index,&(ret_value.string), &highlighted,&sensitive); } else { ret_value.index = -1; ret_value.string = NULL; } XtCallCallbacks(self,XtNcallback,(caddr_t)(&ret_value)); } /*---------------------------------------------------------------* ClassInitialize() This procedure is called by the X toolkit to initialize the class. The hook to this routine is in the class_initialize part of the core part of the class. *---------------------------------------------------------------*/ static void ClassInitialize() { } /* End ClassInitialize */ /*---------------------------------------------------------------* Initialize() This procedure is called by the X toolkit to initialize the widget instance. The hook to this routine is in the initialize part of the core part of the class. *---------------------------------------------------------------*/ /* ARGSUSED */ static void Initialize(request,new) Widget request,new; { XfwfScrolledListWidget w; Arg args[10]; /* static char translations[] = "<Btn1Down>: Select()\n\ <Btn1Up>: Notify()\n"; */ w = (XfwfScrolledListWidget)new; if (CoreData(new).width <= 0) CoreData(new).width = 200; if (CoreData(new).height <= 0) CoreData(new).height = 300; XtSetArg(args[0],XtNuseRight,True); XtSetArg(args[1],XtNwidth,CoreData(new).width); XtSetArg(args[2],XtNheight,CoreData(new).height); XtSetArg(args[3],XtNallowVert,True); XtSetArg(args[4],XtNforceBars,True); MyData(w).viewport = XtCreateManagedWidget("viewport", viewportWidgetClass,(Widget)w,args,5); XtSetArg(args[0],XtNlist,MyData(w).item_array); XtSetArg(args[1],XtNnumberStrings,MyData(w).item_count); XtSetArg(args[2],XtNsensitiveArray,MyData(w).sensitive_array); XtSetArg(args[3],XtNdefaultColumns,1); XtSetArg(args[4],XtNborderWidth,0); XtSetArg(args[5],XtNx,1); XtSetArg(args[6],XtNy,1); XtSetArg(args[7],XtNmaxSelectable,1); /* XtSetArg(args[8],XtNtranslations, XtParseTranslationTable(translations)); */ MyData(w).list = XtCreateManagedWidget("multilist", xfwfMultiListWidgetClass,MyData(w).viewport,args,8); XtAddCallback(MyData(w).list,XtNcallback, (XtCallbackProc)MultiListCallbackHandler,(Widget)w); } /* End Initialize */ /*---------------------------------------------------------------* Realize() This function is called to realize a ScrolledList widget. *---------------------------------------------------------------*/ static void Realize(gw,valueMask,attrs) Widget gw; XtValueMask *valueMask; XSetWindowAttributes *attrs; { XfwfScrolledListWidget w; w = (XfwfScrolledListWidget)gw; XtCreateWindow(gw,InputOutput,(Visual *)CopyFromParent, *valueMask,attrs); XtRealizeWidget(MyData(w).viewport); Resize(gw); } /* End Realize */ /*---------------------------------------------------------------* Destroy() This function is called to destroy a scrolledList widget. *---------------------------------------------------------------*/ static void Destroy(gw) Widget gw; { XfwfScrolledListWidget w; w = (XfwfScrolledListWidget)gw; XtDestroyWidget(MyData(w).viewport); XtDestroyWidget(MyData(w).list); } /* End Destroy */ /*---------------------------------------------------------------* Resize() This function is called to resize a scrolledList widget. *---------------------------------------------------------------*/ static void Resize(gw) Widget gw; { XfwfScrolledListWidget w; w = (XfwfScrolledListWidget)gw; ReCalcChildren(w); } /* End Resize */ /*---------------------------------------------------------------* Boolean SetValues(wcurrent,wrequest,wnew) This isn't inplemented yet, meaning you can't change resources dynamically. *---------------------------------------------------------------*/ /* ARGSUSED */ static Boolean SetValues(wcurrent,wrequest,wnew) Widget wcurrent,wrequest,wnew; { Boolean redraw,recalc; XfwfScrolledListWidget csl,rsl,nsl; csl = (XfwfScrolledListWidget)wcurrent; rsl = (XfwfScrolledListWidget)wrequest; nsl = (XfwfScrolledListWidget)wnew; redraw = False; recalc = False; if ((MyData(csl).item_array != MyData(nsl).item_array) || (MyData(csl).item_count != MyData(nsl).item_count) || (MyData(csl).sensitive_array != MyData(nsl).sensitive_array)) { XfwfScrolledListSetList((Widget)csl, MyData(nsl).item_array, MyData(nsl).item_count,True, MyData(nsl).sensitive_array); redraw = recalc = True; } return(redraw); } /* End SetValues */ /*---------------------------------------------------------------* GeometryManager(w,request,reply) This routine acts as the geometry_manager method for the ScrolledList widget. It is called when a child wants to resize/reposition itself. Currently, we allow all requests. *---------------------------------------------------------------*/ /* ARGSUSED */ static XtGeometryResult GeometryManager(w,request,reply) Widget w; XtWidgetGeometry *request; XtWidgetGeometry *reply; { return(XtGeometryYes); } /* End GeometryManager */ /*---------------------------------------------------------------------------* PreferredGeometry(slw,parent_idea,our_idea) This routine is called by the parent to tell us about the parent's idea of our width and/or height. We then suggest our preference through <our_idea> and return the information to the parent. *---------------------------------------------------------------------------*/ static XtGeometryResult PreferredGeometry(slw,parent_idea,our_idea) XfwfScrolledListWidget slw; XtWidgetGeometry *parent_idea,*our_idea; { Arg multilist_args[2],slist_args[2]; Dimension col_width,row_height,num_rows,current_width,current_height; if (!XtIsRealized((Widget)slw)) return(XtGeometryYes); XtSetArg(multilist_args[0],XtNrowHeight,&row_height); XtSetArg(multilist_args[1],XtNcolumnWidth,&col_width); XtSetArg(slist_args[0],XtNwidth,¤t_width); XtSetArg(slist_args[1],XtNheight,¤t_height); XtGetValues(MyData(slw).list,multilist_args,2); XtGetValues((Widget)slw,slist_args,2); row_height = max(1,row_height); num_rows = max(1,(parent_idea->height / row_height)); our_idea->request_mode = (CWWidth | CWHeight); our_idea->width = col_width; our_idea->height = num_rows * row_height; if ((our_idea->width == current_width) && (our_idea->height == current_height)) { return(XtGeometryNo); /* Prefer To Stay As Is */ } if ((our_idea->width == parent_idea->width) && (our_idea->height == parent_idea->height)) { return(XtGeometryYes); /* Proposed Change Is Fine */ } return(XtGeometryAlmost); } /* End PreferredGeometry */ /*---------------------------------------------------------------------------* L O C A L R O U T I N E S *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------* ReCalcChildren(w) This routine takes a ScrolledList widget <w> and updates the widths and positions of the child widgets. *---------------------------------------------------------------*/ static void ReCalcChildren(w) XfwfScrolledListWidget w; { int wid_h,wid_w; wid_w = CoreData(w).width; wid_h = CoreData(w).height; XtResizeWidget(MyData(w).viewport,wid_w,wid_h,1); } /* End ReCalcChildren */ /*===========================================================================* E X P O R T E D F U N C T I O N S *===========================================================================*/ /*---------------------------------------------------------------------------* XfwfScrolledListSetList(w,newlist,items,resize,sensitive_array) This routine tries to set the string array to the new array <newlist>. <items> is the count of strings. If <items> is 0 and the array is NULL terminated, the number of strings will be automatically counted. The <resize> flag indicates if we want the widget to try to resize itself to hold the new array. The <sensitive_array> parameter (if non-NULL) contains an array of Booleans representing the sensitivity of the list items. *---------------------------------------------------------------------------*/ void XfwfScrolledListSetList(w,newlist,items,resize,sensitive_array) Widget w; char **newlist; int items; Boolean resize; Boolean *sensitive_array; { XfwfScrolledListWidget sw; sw = (XfwfScrolledListWidget)w; XfwfMultiListSetNewData((XfwfMultiListWidget)(MyData(sw).list), newlist,items,0,resize,sensitive_array); MyData(sw).item_array = newlist; MyData(sw).item_count = items; MyData(sw).sensitive_array = sensitive_array; } /* End XfwfScrolledListSetList */ /*---------------------------------------------------------------------------* XfwfScrolledListUnhighlightAll(w) This routine unhighlights all highlighted items in the ScrolledList widget <w>. *---------------------------------------------------------------------------*/ void XfwfScrolledListUnhighlightAll(w) Widget w; { XfwfScrolledListWidget sw; sw = (XfwfScrolledListWidget)w; XfwfMultiListUnhighlightAll((XfwfMultiListWidget)(MyData(sw).list)); } /* End XfwfScrolledListUnhighlightAll */ /*---------------------------------------------------------------------------* XfwfScrolledListHighlightItem(w,item_index) This routine highlights the item with index number <item_index>. *---------------------------------------------------------------------------*/ void XfwfScrolledListHighlightItem(w,item_index) Widget w; int item_index; { XfwfScrolledListWidget sw; sw = (XfwfScrolledListWidget)w; XfwfMultiListHighlightItem((XfwfMultiListWidget)(MyData(sw).list), item_index); } /* End XfwfScrolledListHighlightItem */ /*---------------------------------------------------------------------------* XfwfScrolledListGetHighlighted(w) This routine returns the current highlighted item. *---------------------------------------------------------------------------*/ XfwfScrolledListReturnStruct *XfwfScrolledListGetHighlighted(sw) XfwfScrolledListWidget sw; { XfwfMultiListReturnStruct *pl_ret; XfwfScrolledListReturnStruct sl_ret; sl_ret.multilist = MyData(sw).list; pl_ret = XfwfMultiListGetHighlighted((XfwfMultiListWidget) (MyData(sw).list)); if (pl_ret->num_selected != 0) { sl_ret.string = pl_ret->string; sl_ret.index = pl_ret->item; sl_ret.highlighted = True; } else { sl_ret.string = NULL; sl_ret.index = -1; sl_ret.highlighted = False; } return(&sl_ret); } /* End XfwfScrolledListGetHighlighted */ /*---------------------------------------------------------------------------* XfwfScrolledListIsHighlighted(w,item_index) This routine returns a boolean that indicates if the item with index <item_index> was highlighted or not. *---------------------------------------------------------------------------*/ Boolean XfwfScrolledListIsHighlighted(w,item_index) Widget w; int item_index; { XfwfScrolledListWidget sw; sw = (XfwfScrolledListWidget)w; return(XfwfMultiListIsHighlighted((XfwfMultiListWidget) (MyData(sw).list),item_index)); } /* End XfwfScrolledListIsHighlighted */ /*---------------------------------------------------------------------------* XfwfScrolledListGetItem(w,item_index,str_ptr,high_ptr,sens_ptr) This routine returns information about a numbered item including the name of the item, whether it is highlighted, and its sensitivity. If the item index number does not correspond to an item, False is returned, else True is returned. *---------------------------------------------------------------------------*/ Boolean XfwfScrolledListGetItem(w,item_index,str_ptr,high_ptr,sens_ptr) Widget w; int item_index; String *str_ptr; Boolean *high_ptr,*sens_ptr; { XfwfScrolledListWidget sw; sw = (XfwfScrolledListWidget)w; return(XfwfMultiListGetItemInfo((XfwfMultiListWidget)(MyData(sw).list), item_index,str_ptr,high_ptr,sens_ptr)); } /* End XfwfScrolledListGetItem */ SHAR_EOF fi if test -f 'ScrList.h' then echo shar: "will not over-write existing file 'ScrList.h'" else cat << \SHAR_EOF > 'ScrList.h' /***************************************************************************** ScrolledList.h This file contains the user includes for the ScrolledList widget. ******************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _SCROLLEDLIST_H_ #define _SCROLLEDLIST_H_ extern WidgetClass xfwfScrolledListWidgetClass; typedef struct _XfwfScrolledListClassRec *XfwfScrolledListWidgetClass; typedef struct _XfwfScrolledListRec *XfwfScrolledListWidget; typedef struct { Widget multilist; /* The list widget clicked on */ String string; /* The name of the item clicked on */ int index; /* The index of the item clicked on */ Boolean highlighted; /* Are any items highlighted? */ } XfwfScrolledListReturnStruct; #define XtNlist "list" #define XtNnumberStrings "numberStrings" #ifndef XtNsensitiveArray #define XtNsensitiveArray "sensitiveArray" #endif /*===========================================================================* E X P O R T E D F U N C T I O N S *===========================================================================*/ #if (!NeedFunctionPrototypes) extern void XfwfScrolledListSetList(); extern void XfwfScrolledListUnhighlightAll(); extern XfwfScrolledListReturnStruct * XfwfScrolledListGetHighlighted(); extern Boolean XfwfScrolledListIsHighlighted(); extern Boolean XfwfScrolledListGetItem(); #else extern void XfwfScrolledListSetList(Widget w, char **newlist, int items, int resize, Boolean *sensitive_array); extern void XfwfScrolledListUnhighlightAll(Widget w); extern void XfwfScrolledListHighlightItem(Widget w, int item_index); extern XfwfScrolledListReturnStruct * XfwfScrolledListGetHighlighted(XfwfScrolledListWidget sw); extern Boolean XfwfScrolledListIsHighlighted(Widget w, int item_index); extern Boolean XfwfScrolledListGetItem(Widget w, int item_index, String *str_ptr, Boolean *high_ptr, Boolean *sens_ptr); #endif #endif SHAR_EOF fi if test -f 'ScrListP.h' then echo shar: "will not over-write existing file 'ScrListP.h'" else cat << \SHAR_EOF > 'ScrListP.h' /**************************************************************************** ScrolledListP.h This file is the private definition file for the File Selector Widget. ****************************************************************************/ /* * Author: * Brian Totty * Department of Computer Science * University Of Illinois at Urbana-Champaign * 1304 West Springfield Avenue * Urbana, IL 61801 * * totty@cs.uiuc.edu * */ #ifndef _SCROLLEDLISTP_H_ #define _SCROLLEDLISTP_H_ typedef struct _XfwfScrolledListClassPart { int empty; } XfwfScrolledListClassPart; typedef struct { Widget list; Widget viewport; char **item_array; int item_count; Boolean *sensitive_array; XtCallbackList callback; } XfwfScrolledListPart; typedef struct _XfwfScrolledListClassRec { CoreClassPart core_class; CompositeClassPart composite_class; XfwfScrolledListClassPart scrolledList_class; } XfwfScrolledListClassRec; typedef struct _XfwfScrolledListRec { CorePart core; CompositePart composite; XfwfScrolledListPart scrolledList; } XfwfScrolledListRec; extern XfwfScrolledListClassRec xfwfScrolledListClassRec; #endif SHAR_EOF fi if test -f 'Smart-Go.def' then echo shar: "will not over-write existing file 'Smart-Go.def'" else cat << \SHAR_EOF > 'Smart-Go.def' DEFINITION OF THE SMART-GO FORMAT >From the Dissertation of Anders Kierulf "Smart Game Board: a Workbench for Game-Playing Programs, with Go and Othello as Case Studies" Entered by Greg Hale with permission for distribution. See the many sample files from the 'My Go Teacher' series for examples. ------------ A standard file format to exchange machine-readable games, problems, and opening libraries would save time and work. That goal may not be too far away. A standard for exchanging collections of Othello games is being worked out by Erik Jensen, Emmanuel Lazard, and Brian Rose in collaboration with the author. For Go, a new standard has recently been proposed [Connelley 89, High 89]; it seems to suffer from a wealth of features, but any standard for exchanging Go games is welcome, and will be supported by the Smart Game Board. The current file format is specialized for the needs of the Smart Game Board. It is based on an earlier proposal for a standard for Go games [Kierulf 87b] which was not widely adopted. The following description is not a new proposal; it is intended for those who want to read or white files that are compatible with the Smart Game Board. The game collections (documents) of the Smart Game Board are stored as text files. This has the advantage that files can be manipulated with standard text utilities, and that it's easier to exchange games by electronic mail. The disadvantage is that text files are less compact than binary files. The Smart Game Board stores the game trees of each document, with all their nodes and properties, and nothing more. Thus the file format reflects the regular internal structure of a tree of property lists. There are no exceptions; if a game needs to store some information on file with the document, a (game-specific) property must be defined for that purpose. I will first define the syntax of the game collections, then discuss syntax and semantic of various properties. GAME COLLECTIONS A collection of game sis simply the concatenation of the game trees. The structure of each tree is indicated by parentheses. A tree is written as "(" followed by a sequence of nodes (as long as the tree is unbranched) and a tree for each son, and terminated by ")". Each node is preceded by a separator, and contains a list of zero or more properties. Thus the main branch of the game is stored first in the file, and programs can easily read that part (until the first closing parenthesis) and ignore the rest. The conventions of EBNF are discussed in [Wirth 85]. A quick summary: "..." : terminal symbols [...] : option: occurs at most once {...} : repetition: any number of times, including zero (...) : grouping | : exclusive-or The overall definition of the file format is as follows: Collection = {GameTree}. GameTree = "(" Sequence {GameTree} ")". Sequence = Node {Node}. Node = ";" {Property} Any text before the first opening parenthesis is reserved for future extensions and is ignored when reading a file. Spaces, tabs, line breaks and so on can be inserted anywhere between properties and are also ignored. GAME-INDEPENDENT PROPERTIES Each property is identified by one or two capital letters. The property value is enclosed in brackets; lists of points or integers are written as a sequence of property values. Within text, a closing bracket is prefixed by a backslash, and a backslash is doubled. Moves and points are game-specific and are defined later. Property = PropIdent PropValue {PropValue}. PropIdent = UpperCase [UpperCase | Digit]. PropValue = "[" [Number | Text | Real | Triple | Color | Move | Point | ... ] "]" Number = ["+" | "-"] Digit {Digit}. Text = { any character; "\]" = "]", "\\" = "\"}. Real = { Number ["." {Digit}]. Triple = ("1" | "2"). Color = ("B" | "W"). Move and Point are game-specific and are described later. The following properties are understood by all games. The property type is given in brackets. "B" : Black move [move, game-specific] "W" : White move [move, game-specific] "C" : Comment [Text] "N" : Node Name [Text] The purpose of providing both a node name and a comment is to have a short identifier like "doesn't work" or "Dia. 15" that can be displayed directly with the properties of the node, even if the comment is turned off or shown in a separate window. There is no limit to the length of texts; programs must be able to ignore the rest of texts that are too long for them to handle. Reasonable limits are 32 characters for node names and at least 2000 characters for comments. "V" : Node value [number] Positive values are good for Black, negative values are good for White. The interpretation of particular values is game-specific. "CH": Check mark [triple] "GB": good for black [triple] "GW": good for white [triple] "TE": good move (tesuji) [triple] "BM": bad move [triple] The normal value for such properties is one, properties that are doubled for emphasis have the value two. "BL": time left for Black [real] "WL": time left for White [real] All times are given in seconds, or fractions thereof {Hale: these can be negative, indicating player is playing past time limit set}. "FG": figure [none] The figure property is used to divide a game into different figures for printing: a new figure starts at the node with a figure property. "AB": add black stones [point list, game specific] "AW": add white stones [point list, game specific] "AE": add empty stones [point list, game specific] "PL": player to play first [color] The above properties are used to set up positions in games with only black and white stones. The following properties are all part of the game info: "GN": game name [text] "GC": game comment [text] "EV": event (tournament) [text] "RO": round [text] "DT": date [text] "PC": place [text] "PB": black player name [text] "PW": white player name [text] "RE": result, outcome [text] "US": user (who entered game) [text] "TM": time limit per player [text] "SO": source (book, journal...) [text] The format in these game-info strings is free, but to be able to search for specific games in game collections, it is recommended to adhere to the following conventions: - Date is ISO-standard: "YYYY-MM-DD". - Result as "0" (zero) for a draw, "B+score" for a black win, and "W+score" for a white win, e.g. "B+2.5", "W+64" - Time limit as a number, in minutes. In addition, names, events, and places should be spelled the same im all games. The following properties may only be present at the root node: "GM": game [number] (Go=1, Othello=2, chess=3, Nine Mens Morris=5) "SZ": board size [number] "VW": partial view [point list, game-specific] "BS": black species [number] (human=0, modem=-1, computer>0) "WS": white species [number] The game number helps the program reject games it cannot handle (this property was mandatory as long as an application could play different games). The view gives two corner points of a rectangular subsection; an empty list denotes the whole board. The species denotes the kind of player (the source of the more input), with different version of computer algorithms denoted by positive numbers (default algorithm = 1). Computer algorithms may add the following properties: "EL": evaluation of computer move [number] "EX": expected next move [move, game-specific] Some games support markings on the board: selected points, triangles/crosses, or letters (a sequence of letters is shown on the points given in the list, starting with "A"): "SL": selected points [point list, game-specific] "M" : marked points [point list, game-specific] "L" : letters on points [point list, game-specific] GO-SPECIFIC PROPERTIES In my proposal for a standard [Kierul 87b], I intentionally broke with the tradition of labeling moves (and points) with letters "A"-"T" (excluding "i") and numbers 1-19. Two lowercase letters in the range "a"-"s" were used instead, for reasons of simplicity and compactness. This was criticized mainly because it was not human-readable, but as that is not an important feature of this file format, I continue to use that notation. (Hale: diagram omitted) The first letter designated the column (left to right), the second the row (top to bottom). The upper left part of the board is used for smaller boards, e.g. letters "a"-"m" for 13*13. (Column before row follows the principle "horizontal before vertical" used in x-y coordinate systems. The upper left corner as origin of the board corresponds to the way we read, and most modern computers use it as origin of the screen coordinates to simplify integration of text and graphics.) A pass move is written as "tt". The board must be quadratic, no smaller than 2x2, and no larger than 19x19. Additional game info properties are defined for Go: "BR": Black's rank [text] "WR": White's rank [text] "HA": handicap [number] "KM": komi [real] Sets of board points can be marked as territory, as secure stones, or just as a region of the board (e.g. to designate eye space): "TB": Black's territory [point list] "TW": White's territory [point list] "SC": secure stones [point list] "RG": region of the board [point list] SHAR_EOF fi if test -f 'Spec.io' then echo shar: "will not over-write existing file 'Spec.io'" else cat << \SHAR_EOF > 'Spec.io' INTERFACE SPECIFICATION FOR MGT If you wish to add a new interface to mgt, these are the functions you need to come up with. void open() Initialize interface. Any *interface* specific initialization is done here. void close() Leave the interface. void refreshIO() update screen to look like memory image. Somewhat curses specific. Probably will be a null function null(){} in most interfaces. void plotPiece(pBoard b, int i, int j) Plots the piece contained in b at i,j on the real screen. Board is read by call boardGet(b, i, j) which returns one of P_NOTHING, P_BLACK, P_WHITE, P_DAME, P_BLACKTERR, or P_WHITETERR. void clearComment() Clears comment window void initBoard() Draw a blank board of size 'boardsize' void clearScreen() clears screen. int idle(nodep n) Gets the next command. Acts like an event driven loop. Waits for keystroke. Returns a command casted to an int to indicate the command for doit.c to process. void drawTree(nodep n) Show the variations that are available in the var list on the right when starting at node n. (in Ascii version) Interface-local variables exists to handle scrolling. scrolling should be handled by the interface alone. void highlightLast(int x, y, movenum, turn) Show last move number, current turn, whose move it is, and the prisoner count. turn==0 means Black just moved. If x and y are equal to PASSVAL then the move was a pass. Use these to get current player turn and prisoner count extern int prisoners[black=0,white=1] ; extern int curPlayer; void readEnv(char **env) Check *env for environment string. Increment it to point to the first character not used. void notifyMessage(char *s) Print single line message someplace. void notifyClear() Clear notify message area int queryStr(char *query, char *dst, int maxLen) Print query out. Get at most maxLen chars into dst. Return length of the result. void setCursor(int i, int j) Move cursor (pointer) to position i,j on go board void plotMark(pBoard b,int i,int j) Plot mark at position i,j on displayed board. DOES NOT modify *b. Mark is erased by call to plotPiece void plotLetter(int i, int j, char c) Puts letter c on the screen at board position i,j int getPoint() Allow user to specify a board position (Cursor keys, mouse, etc) Used when scoring the game. Uses globals xcur and ycur to store the position. The return value can be C_QUIT to abort score. C_SCORE to calculate the score. C_REDRAW to redraw screen, or C_NOTHING to kill the group we're on right now. void editComment(char *inp, char **out) Edit a comment. inp contains the input comment to be edited. THIS MUST BE free()'d. out contains the return pointer. It should be allocated to the appropriate size and the new edited comment should be placed in the allocated space. int askYN(char *query, int defalt) Prompt user with query. The query will NOT end in " (y/n)? " If needed by the interface, this should be added here. Returns 1 for yes, 0 for no. defalt contains the default response (1 for yes, 0 for no). void notifyError(char *errormsg) Display error message. Give user a chance to see it, and clear message. void displayInfo(char *s) Formats and displays string s as a list of game information. Each informational item starts on its own line but may contain newlines. Token getInfoToChange() Passes back an informational token to change, or t_EOF to escape from the info editor. (Scrolling of the info region should be handled internally here.) void editInfo(char *input, char **output, property info_item) Edits the info item corresponding to info_item. The current text is given in input which should be freed. The replacement text should be put in *output which needs to be allocated by this function. (This works like the comment editor.) SHAR_EOF fi if test -f 'advunix.c' then echo shar: "will not over-write existing file 'advunix.c'" else cat << \SHAR_EOF > 'advunix.c' /* advunix.c * * Copyright (c) 1992 by Chien-Min Wang. * All rights reserved. */ #include <stdio.h> #include <errno.h> #include <fcntl.h> #include "advunix.h" /* print system call error message and terminate */ void syserr(msg) char *msg; { extern int errno, sys_nerr; extern char *sys_errlist[]; fprintf(stderr, "ERROR: %s (%d", msg, errno); if (errno > 0 && errno < sys_nerr) fprintf(stderr, "; %s)\n", sys_errlist[errno]); else fprintf(stderr, ")\n"); exit(1); } /* print error message and terminate */ void fatal(msg) char *msg; { fprintf(stderr, "ERROR: %s\n", msg); exit(1); } /* turn blocking on or off */ void setblock(fd, on) int fd; BOOLEAN on; { static int blockf, nonblockf; static BOOLEAN first = TRUE; int flags; if (first) { first = FALSE; if ((flags = fcntl(fd, F_GETFL, 0)) == -1) syserr("fnctl"); blockf = flags & ~O_NDELAY; /* make sure O_NDELAY is off */ nonblockf = flags | O_NDELAY; /* make sure O_NDELAY is on */ } if (fcntl(fd, F_SETFL, on ? blockf : nonblockf) == -1) syserr("fcntl2"); } static BOOLEAN inbuf = FALSE; static char cbuf; /* test if a character is ready */ BOOLEAN cready() { if (inbuf) return TRUE; setblock(0, FALSE); switch (read(0, &cbuf, 1)) { case -1: if(errno != EWOULDBLOCK) /* test if 4.2BSD style */ syserr("read"); case 0: return(inbuf = FALSE); /* could be EOF too */ default: return(inbuf = TRUE); } } /* get a character */ int cget() { if (inbuf) { inbuf = FALSE; return(cbuf & 0377); /* prevent sign extension */ } setblock(0, TRUE); switch (read(0, &cbuf, 1)) { case -1: syserr("read"); case 0: return(-1); /* must be EOF */ default: return(cbuf & 0377); } } /* get a line of characters */ BOOLEAN lget(s, max) char *s; int max; { register int i; char c; i = 0; if (inbuf) { s[i++] = cbuf; inbuf = FALSE; } setblock(0, FALSE); while (TRUE) { switch (read(0, &c, 1)) { case -1: if(errno != EWOULDBLOCK) /* test if 4.2BSD style */ syserr("read"); case 0: if (i >= max) fatal("lget overflow"); s[i] = '\0'; return(FALSE); /* could be EOF too */ default: if (i >= max) fatal("lget overflow"); s[i++] = c; if ((c == '\n') || (c == '\r')) { if (i >= max) fatal("lget overflow"); s[i] = '\0'; return(TRUE); } } } } SHAR_EOF fi if test -f 'advunix.h' then echo shar: "will not over-write existing file 'advunix.h'" else cat << \SHAR_EOF > 'advunix.h' /* advunix.h * * Copyright (c) 1992 by Chien-Min Wang. * All rights reserved. */ #define lowbyte(w) ((w) & 0377) #define highbyte(w) lowbyte((w) >> 8) #undef TRUE #undef FALSE typedef enum {FALSE, TRUE} BOOLEAN; SHAR_EOF fi if test -f 'build.c' then echo shar: "will not over-write existing file 'build.c'" else cat << \SHAR_EOF > 'build.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" int lastMoveX, lastMoveY, moveNum, lastTurn; coordList *lastletters = 0, *lastmarks; coordList *marks = 0; coordList *letters = 0; FUNCTION void clearLast() { lastMoveX = lastMoveY = -1; moveNum = 0; } FUNCTION void highlightLast() { extern Token curPlayer; if (lastMoveX >= 0 && moveNum > 0 && lastTurn != (int) t_EOF) curPlayer = lastTurn ? t_Black : t_White; (*io->highlightLast) (lastMoveX, lastMoveY, moveNum, lastTurn); } FUNCTION void doPlace(p, b, t) property *p; pBoard b; piece t; { coordList *list; list = p->data.stones; while (list) { placeStone(b, list->x, list->y, t); list = list->next; } if (p->t == t_Black || p->t == t_White) moveNum++; } FUNCTION void doProps(p, b) property *p; pBoard b; { letters = NULL; marks = NULL; while (p) { switch (p->t) { case t_White: BUG("t_White "); doPlace(p, b, P_WHITE); break; case t_Black: BUG("t_Black "); doPlace(p, b, P_BLACK); break; case t_AddWhite: BUG("t_AddWhite "); doPlace(p, b, P_WHITE); break; case t_AddBlack: BUG("t_AddBlack "); doPlace(p, b, P_BLACK); break; case t_AddEmpty: BUG("t_AddEmpty "); doPlace(p, b, P_NOTHING); break; case t_Comment: break; case t_Pass: moveNum++; break; case t_Mark: marks = p->data.stones; break; case t_Letter: letters = p->data.stones; BUG("t_Letter "); break; default: BUG("default "); } p = p->next; } } static void setLastMovePos(p) property *p; { lastTurn = p->t == t_White ? 1 : 0; if (p->data.stones) { lastMoveX = p->data.stones->x; lastMoveY = p->data.stones->y; } else lastMoveX = lastMoveY = -1; } FUNCTION void doPropComment(n) nodep n; { property *p; if (p = getprop(n, t_Comment)) (*io->displayComment) (p->data.comment); if (p = getprop(n, t_Black)) setLastMovePos(p); else if (p = getprop(n, t_White)) setLastMovePos(p); if (p = getprop(n, t_Pass)) { lastTurn = p->data.player == t_White ? 1 : 0; lastMoveX = lastMoveY = PASSVAL; } } FUNCTION void buildTree0(n, b) nodep n; pBoard b; { BUG("parent >"); if (n) { buildTree0(n->parent, b); BUG("\nprops:"); doProps(n->p, b); } } FUNCTION void buildTree(n, b) nodep n; pBoard b; { extern int prisoners[]; prisoners[0] = 0; prisoners[1] = 0; boardClear(b); (*io->clearComment) (); BUG("buildTree:\n"); clearLast(); buildTree0(n, b); doPropComment(n); } FUNCTION void setPiece(b, i, j, p) pBoard b; int i, j; piece p; { boardSet(b, i, j, p); (*io->plotPiece) (b, i, j); } FUNCTION void updateBoard(dst, new) pBoard dst, new; /* update dst to look like new */ { extern int prisoners[]; int i, j; coordList *cl; for (cl = lastmarks; cl; cl = cl->next) (*io->plotPiece) (new, cl->x, cl->y); for (cl = lastletters; cl; cl = cl->next) (*io->plotPiece) (new, cl->x, cl->y); lastmarks = marks; lastletters = letters; for (i = boardsize; i--;) for (j = boardsize; j--;) { if (boardGet(new, i, j) != boardGet(dst, i, j)) { setPiece(dst, i, j, boardGet(new, i, j)); } } if (marks) { for (cl = marks; cl; cl = cl->next) (*io->plotMark) (new, cl->x, cl->y); marks = NULL; } if (letters) { for (i = 0, cl = letters; cl; cl = cl->next, i++) (*io->plotLetter) (cl->x, cl->y, (i % 26) + 'a'); letters = NULL; } } SHAR_EOF fi if test -f 'comment.c' then echo shar: "will not over-write existing file 'comment.c'" else cat << \SHAR_EOF > 'comment.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" #include <string.h> #include <ctype.h> short clines; char cbuf[MAXCOMMENTLINES][MAXCOMMENTWIDTH]; char *empty = ""; FUNCTION char *commentGet(line) /* int */ int line; { if (line < clines) return cbuf[line]; else return empty; } FUNCTION int commentLines() { return clines; } FUNCTION void formatComment(comment, width) char *comment; int width; { char *partstart, *dest, c; int len, partlen, wordlen; clines = 0; width = MIN(width, MAXCOMMENTWIDTH - 1); wordlen = partlen = len = 0; dest = cbuf[0]; if (*comment == '\n') comment++; partstart = comment; do { c = *(comment++); len++; partlen++; wordlen++; if (c == ' ') wordlen = 0; else if (c == '\n' && *(comment - 2) == ' ' && *comment != '\n') { partlen--; len--; strncpy(dest, partstart, partlen); dest += partlen; partstart = comment; wordlen = partlen = 0; } else if (c == '\n' || !c) { strncpy(dest, partstart, partlen - 1); *(dest + partlen - 1) = 0; len = partlen = wordlen = 0; dest = cbuf[++clines]; partstart = comment; } if (len == width) { if (len == wordlen) wordlen = 0; else len = partlen - wordlen; strncpy(dest, partstart, len); partstart += len; *(dest + len) = 0; len = partlen = wordlen; dest = cbuf[++clines]; } } while (c && clines < MAXCOMMENTLINES); } SHAR_EOF fi if test -f 'doit.c' then echo shar: "will not over-write existing file 'doit.c'" else cat << \SHAR_EOF > 'doit.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" int xcur, ycur; Token curPlayer; int change; int madechanges; int searchNodeNum; int ispl = 0; FUNCTION int okChange() { if (tutor) { (*io->notifyError) ("Can't edit in tutor mode."); return 0; } if ((!change) && ((*io->askYN) ("Modify tree", 0))) change = 1; if (change) madechanges = 1; return change; } FUNCTION int okExit(root) nodep root; { if (mailFlag) { if (madechanges) { if (!(*io->askYN) ("Save", 1)) { retVal = 1; return 1; } if (writeTree(saveName, root)) return 0; return 1; } retVal = 1; return 1; } if (madechanges) { if ((*io->askYN) ("Unsaved changes. Exit without saving", 0)) return 1; return 0; } return 1; } FUNCTION nodep search(n) /* return 0 on failure */ nodep n; { nodep s; if (!n || n->nodeNum == searchNodeNum) return n; s = search(child(n)); if (s && s->nodeNum == searchNodeNum) return s; s = search(nextSibling(n)); if (s && s->nodeNum == searchNodeNum) return s; return (nodep) 0; } FUNCTION void step(n, b) nodep n; pBoard b; { board temp; buildTree(n, &temp); updateBoard(b, &temp); (*io->drawTree) (n); (*io->refreshIO) (); highlightLast(); } FUNCTION void stepDown(n, b) nodep n; pBoard b; { board temp; (*io->clearComment) (); copyBoard(b, &temp); doProps(n->p, &temp); doPropComment(n); updateBoard(b, &temp); (*io->drawTree) (n); (*io->refreshIO) (); highlightLast(); }; static char *color[] = { "Black", "White" }; int adjust(val, halfk, ksign) int val, halfk, ksign; { if (!halfk) return val; if (val * ksign >= 0) return val; return val + ksign; } FUNCTION void doScore(b, curNode) pBoard b; nodep curNode; { extern int prisoners[]; int savepris[2], lastpris[2]; char out[200]; command c; property *p; board new, old, last; int score[2], scored; char komicopy[10]; int intkomi, halfkomi, kptr, komisign, winner, diff; winner = -1; scored = 0; lastpris[1] = savepris[1] = prisoners[1]; lastpris[0] = savepris[0] = prisoners[0]; copyBoard(b, &old); copyBoard(b, &last); copyBoard(b, &new); (*io->notifyClear) (); (*io->notifyMessage) ("return score, space kill, u undo, q quit"); do { c = (command) (*io->getPoint) (); if (c == C_MOVE && (new.b[xcur][ycur] == P_WHITE || new.b[xcur][ycur] == P_BLACK) ) { if (scored) { scored = 0; copyBoard(&last, &new); prisoners[1] = lastpris[1]; prisoners[0] = lastpris[0]; } copyBoard(&new, &last); lastpris[1] = prisoners[1]; lastpris[0] = prisoners[0]; removeStones(&new, xcur, ycur); updateBoard(b, &new); } if (c == C_UNDO) { copyBoard(&last, &new); prisoners[1] = lastpris[1]; prisoners[0] = lastpris[0]; updateBoard(b, &new); } if (c == C_SCORE && !scored) { copyBoard(&new, &last); lastpris[1] = prisoners[1]; lastpris[0] = prisoners[0]; scoreBoard(&new, score); updateBoard(b, &new); if (info[t_Komi - FIRSTINFO]) { halfkomi = 0; for (kptr = 0; info[t_Komi - FIRSTINFO][kptr]; kptr++) { if (info[t_Komi - FIRSTINFO][kptr] == '.') { kptr++; if (info[t_Komi - FIRSTINFO][kptr] >= '1' && info[t_Komi - FIRSTINFO][kptr] <= '9') halfkomi = 1; break; } komicopy[kptr] = info[t_Komi - FIRSTINFO][kptr]; } komicopy[kptr] = 0; intkomi = atoi(komicopy); komisign = 0; if (komicopy[0] == '-' || intkomi < 0) komisign = -1; else if (intkomi > 0 || halfkomi) komisign = 1; sprintf(komicopy, "+ %s ", info[t_Komi - FIRSTINFO]); } else { komisign = intkomi = halfkomi = 0; strcpy(komicopy, ""); } diff = score[1] + prisoners[0] - score[0] - prisoners[1] + intkomi; if (!diff) { if (halfkomi) { if (komisign > 0) winner = 1; else if (komisign < 0) winner = 0; } else winner = 2; } else winner = diff > 0 ? 1 : 0; diff = adjust(diff, halfkomi, komisign); sprintf(out, "Black: %d + %d = %d\n\nWhite: %d + %d %s= %s%d%s\n\n", score[0], prisoners[1], score[0] + prisoners[1], score[1], prisoners[0], komicopy, (!diff) && halfkomi && (komisign == -1) ? "-" : "", adjust(score[1] + prisoners[0] + intkomi, halfkomi, komisign), halfkomi ? ".5" : ""); if (winner == 2) sprintf(out + strlen(out), "Tie game."); else sprintf(out + strlen(out), "%s wins by %d%s", color[winner], abs(diff), halfkomi ? ".5" : ""); (*io->clearComment) (); (*io->displayComment) (out); scored = 1; } } while (c != C_QUIT); if (scored && (*io->askYN) ("Keep comment", 1) && okChange()) replaceComment(curNode, out); else { (*io->clearComment) (); if (p = getprop(curNode, t_Comment)) (*io->displayComment) (p->data.comment); } prisoners[0] = savepris[0]; prisoners[1] = savepris[1]; (*io->notifyClear) (); updateBoard(b, &old); } static void initBoard(b) pBoard b; { extern coordList *lastmarks, *lastletters; boardClear(b); (*io->initializeBoard) (); lastletters = lastmarks = 0; } FUNCTION nodep loadFile(filename, root, b) char *filename; nodep root; board *b; { openfile(filename); if (input) { madechanges = change = 0; freeNode(root); initNodes(); readInit(); root = parse(0); fclose(input); if (!root) root = newNode(); initBoard(b); (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); xcur = ycur = 0; } else (*io->notifyError) ("Unable to load file."); return root; } FUNCTION nodep makeTutor(nod, tok, x, y) nodep nod; Token tok; int x, y; { property *prop; if (!nod->child) return 0; nod = nod->child; while (!((prop = getprop(nod, tok)) && getCoord(x, y, prop->data.stones))) { if (!nod->nextSibling) return 0; nod = nod->nextSibling; } return nod; } static char *infotitle[] = { "Game name: ", "Event: ", "rouNd: ", "Date: ", "Place: ", "Time limit: ", "Result: ", "Comment: ", "sOurce: ", "User: ", "Komi: " }; static void showinfo() { char infoarray[4000]; char *infostr; int p; infostr = infoarray; sprintf(infostr, "Size: %d", boardsize); while (*infostr) infostr++; if (info[(int) t_Komi - FIRSTINFO]) { sprintf(infostr, " Komi: %s", info[(int) t_Komi - FIRSTINFO]); while (*infostr) infostr++; } if (handicap) { sprintf(infostr, " Handicap: %d", handicap); while (*infostr) infostr++; } *infostr = '\n'; infostr++; if (info[0] || info[1]) { sprintf(infostr, "Black: %s%s%s\n", info[0] ? info[0] : "", info[0] && info[1] ? ", " : "", info[1] ? info[1] : ""); while (*infostr) infostr++; } if (info[2] || info[3]) { sprintf(infostr, "White: %s%s%s\n", info[2] ? info[2] : "", info[2] && info[3] ? ", " : "", info[3] ? info[3] : ""); while (*infostr) infostr++; } for (p = 0; p <= LASTINFO - FIRSTINFO - 4; p++) { if (info[p + 4]) { sprintf(infostr, "%s%s\n", infotitle[p], info[p + 4]); while (*infostr) infostr++; } } *infostr = 0; (*io->displayInfo) (infoarray); } #define BUFFERSIZE 50 static int doinfo() { Token change; int sizechanged, value; char buffer[BUFFERSIZE + 1]; char *current; sizechanged = 0; do { showinfo(); change = (Token) (*io->getInfoToChange) (); if (change == t_EOF) break; if (!okChange()) continue; if (change == t_Size) { sprintf(buffer, "%d", boardsize); current = dupStr(buffer); (*io->editInfo) (current, ¤t, t_Size); if (current) { value = atoi(current); if (value > 1 && value < 20) { if (value != boardsize) sizechanged = 1; boardsize = value; } free(current); } } else if (change == t_Handicap) { sprintf(buffer, "%d", handicap); current = dupStr(buffer); (*io->editInfo) (current, ¤t, t_Handicap); if (current) { handicap = atoi(current); free(current); } } else { (*io->editInfo) (info[(int) change - FIRSTINFO], &info[(int) change - FIRSTINFO], change); if (!strlen(info[(int) change - FIRSTINFO])) { free(info[(int) change - FIRSTINFO]); info[(int) change - FIRSTINFO] = 0; } } } while (1); return sizechanged; } static void savescreen(bord) board *bord; { char fname[75]; int i, j; FILE *out; extern coordList *lastletters; extern int prisoners[]; coordList *let; char local[19][19]; if ((*io->queryStr) ("Save screen: ", fname, 74)) { if (out = fopen(fname, "a+t")) { fprintf(out, "%s to play.\n\n", curPlayer == t_Black ? "Black" : "White"); fputs(" ", out); for (i = 0; i < boardsize; i++) { fputc(' ', out); fputc(i + 'A' + ((i + 'A' >= 'I') ? 1 : 0), out); } fputc('\n', out); for (j = 0; j < boardsize; j++) for (i = 0; i < boardsize; i++) { local[i][j] = ' '; switch (bord->b[i][j]) { case P_WHITE: local[i][j] = 'O'; break; case P_BLACK: local[i][j] = '#'; break; case P_NOTHING: default: local[i][j] = '.'; break; } } let = lastletters; i = 0; while (let) { local[let->x][let->y] = i + 'a'; i++; i %= 26; let = let->next; } for (j = 0; j < boardsize; j++) { fprintf(out, "%2d ", boardsize - j); for (i = 0; i < boardsize; i++) { fputc(local[i][j], out); fputc(' ', out); } fprintf(out, "%2d", boardsize - j); if ( (j == boardsize / 2) && (prisoners[0] || prisoners[1])) fprintf(out, " Captured #: %d Captured O: %d", prisoners[0], prisoners[1]); fputc('\n', out); } fputs(" ", out); for (i = 0; i < boardsize; i++) { fputc(' ', out); fputc(i + 'A' + ((i + 'A' >= 'I') ? 1 : 0), out); } fputs("\n\n", out); for (i = 0; i < commentLines(); i++) { fputs(commentGet(i), out); putc('\n', out); } fclose(out); } else (*io->notifyError) ("Unable to open file."); } } FUNCTION void doit() { int quitflg, i; nodep root, curNode; board theBoard; extern coordList *lastletters, *lastmarks; curPlayer = t_Black; xcur = ycur = quitflg = 0; root = 0; madechanges = 0; change = 1; if (input != stdin) { root = parse(0); fclose(input); change = 0; } if (!root) root = newNode(); curNode = root; initBoard(&theBoard); (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); if (mailFlag) { while (curNode->child) curNode = treeDown(curNode); change = 1; } step(curNode, &theBoard); while (!quitflg) { nodep tNode; command c; property *prop; if (prop = getprop(curNode, t_Player)) { extern Token lastTurn; curPlayer = prop->data.player; lastTurn = t_EOF; ispl = 1; } else ispl = 0; c = (command) (*io->idle) (curNode); if ((int) c >= (int) C_CHOSECHILD && (int) c < (int) C_NEXTCMD) { nodep new; new = nthChild(curNode, (int) c - (int) C_CHOSECHILD); if (new) { curNode = nthChild(curNode, (int) c - (int) C_CHOSECHILD); step(curNode, &theBoard); } } else switch (c) { case C_LOAD: if (okExit(root)) { char filename[50]; if ((*io->queryStr) ("Load file? ", filename, 48)) { root = curNode = loadFile(filename, root, &theBoard); step(curNode, &theBoard); } } break; case C_BACKFILE: if (currentfile > 0 && okExit(root)) { currentfile--; root = curNode = loadFile(files[currentfile], root, &theBoard); step(curNode, &theBoard); } else (*io->notifyError) ("No previous file."); break; case C_NEXTFILE: if (currentfile + 1 < filecount && okExit(root)) { currentfile++; root = curNode = loadFile(files[currentfile], root, &theBoard); step(curNode, &theBoard); } else (*io->notifyError) ("No next file."); break; case C_INFO: if (doinfo()) initBoard(&theBoard); step(curNode, &theBoard); if (xcur >= boardsize) xcur = boardsize - 1; if (ycur >= boardsize) ycur = boardsize - 1; break; case C_SAVESCREEN: savescreen(&theBoard); break; case C_REDRAW: { int savex, savey; savex = xcur; savey = ycur; initBoard(&theBoard); (*io->refreshIO) (); step(curNode, &theBoard); xcur = savex; ycur = savey; break; } case C_NOTHING: break; case C_TOPLAY: if (okChange()) addPlayer(curNode, (curPlayer == t_Black) ? t_White : t_Black); break; case C_PASSMOVE:{ int mod_cur_node; mod_cur_node = passMove(curNode, curPlayer); if (mod_cur_node) step(curNode, &theBoard); else { curNode = treeDown(curNode); stepDown(curNode, &theBoard); } } break; case C_TOGGLESTONE:{ extern Token lastTurn; curPlayer = (curPlayer == t_Black) ? t_White : t_Black; lastTurn = t_EOF; } break; case C_TUTORSWAP: tutor = !tutor; break; case C_MOVE: if (tutor) { nodep save; save = curNode; if (curNode = makeTutor(curNode, curPlayer, xcur, ycur)) { step(curNode, &theBoard); } else { (*io->notifyError) ("Wrong move."); curNode = save;; } } else { if (okChange() && legal(&theBoard, curNode, curPlayer, xcur, ycur)) { int mod_cur_node; mod_cur_node = makeMove(curNode, curPlayer, xcur, ycur); curPlayer = (curPlayer == t_Black) ? t_White : t_Black; if (mod_cur_node) step(curNode, &theBoard); else { curNode = treeDown(curNode); stepDown(curNode, &theBoard); } } } break; case C_ADDVAR: if (okChange()) { makeVariation(curNode); step(curNode, &theBoard); } break; case C_DELNODE: if (okChange()) { deleteNode(&curNode); step(curNode, &theBoard); } break; case C_PASTE: if (okChange()) if (pasteTree(curNode)) step(curNode, &theBoard); else (*io->notifyError) ("Nothing to paste."); break; case C_TREECUT: if (okChange()) { nodep prevNode; int savex, savey; savex = xcur; savey = ycur; prevNode = curNode->parent; cutTree(curNode); curNode = prevNode; if (!curNode) { initNodes(); root = curNode = newNode(); } step(curNode, &theBoard); xcur = savex; ycur = savey; break; } case C_ADDBLACK: if (okChange()) { coordList *cl; property *prop; if (boardGet(&theBoard, xcur, ycur) == P_BLACK) { addStone(curNode, t_AddEmpty, xcur, ycur); setPiece(&theBoard, xcur, ycur, P_NOTHING); } else { addStone(curNode, t_AddBlack, xcur, ycur); setPiece(&theBoard, xcur, ycur, P_BLACK); } if (prop = getprop(curNode, t_Letter)) lastletters = prop->data.stones; for (i = 0, cl = lastletters; cl; i++, cl = cl->next) (*io->plotLetter) (cl->x, cl->y, i % 26 + 'a'); } break; case C_ADDWHITE: if (okChange()) { coordList *cl; property *prop; if (boardGet(&theBoard, xcur, ycur) == P_WHITE) { addStone(curNode, t_AddEmpty, xcur, ycur); setPiece(&theBoard, xcur, ycur, P_NOTHING); } else { addStone(curNode, t_AddWhite, xcur, ycur); setPiece(&theBoard, xcur, ycur, P_WHITE); } if (prop = getprop(curNode, t_Letter)) lastletters = prop->data.stones; for (i = 0, cl = lastletters; cl; i++, cl = cl->next) (*io->plotLetter) (cl->x, cl->y, i % 26 + 'a'); } break; case C_ADDLETTER: if (okChange()) { int sx, sy; for (; lastletters; lastletters = lastletters->next) (*io->plotPiece) (&theBoard, lastletters->x, lastletters->y); lastletters = 0; sx = xcur; sy = ycur; if (addMark(curNode, t_Letter, xcur, ycur)) (*io->plotPiece) (&theBoard, xcur, ycur); stepDown(curNode, &theBoard); xcur = sx; ycur = sy; } break; case C_ADDMARK: if (okChange()) { int sx, sy; for (; lastmarks; lastmarks = lastmarks->next) (*io->plotPiece) (&theBoard, lastmarks->x, lastmarks->y); lastmarks = 0; sx = xcur; sy = ycur; if (addMark(curNode, t_Mark, xcur, ycur)) (*io->plotPiece) (&theBoard, xcur, ycur); stepDown(curNode, &theBoard); xcur = sx; ycur = sy; } break; case C_EDCOMMENT: if (okChange()) { edComment(curNode); step(curNode, &theBoard); } break; case C_ADDNAME: if (okChange()) { makeName(curNode); step(curNode, &theBoard); } break; case C_DOWN: tNode = treeDown(curNode); if (tNode != curNode) { curNode = tNode; stepDown(curNode, &theBoard); } break; case C_UP: curNode = treeUp(curNode); step(curNode, &theBoard); break; case C_WALKDOWN: tNode = treeNext(curNode); if (tNode->parent == curNode) { stepDown(tNode, &theBoard); } else { step(tNode, &theBoard); } curNode = tNode; break; case C_WALKUP: curNode = treeLast(curNode); step(curNode, &theBoard); break; case C_SEARCHCOMMENT: { nodep tBegin; tBegin = curNode; tNode = curNode; do { tNode = treeNext(tNode); } while (tNode != tBegin && !getprop(tNode, t_Comment)); if (tNode != curNode) { if (tNode->parent == curNode) { stepDown(tNode, &theBoard); } else { step(tNode, &theBoard); } curNode = tNode; } } break; case C_SEARCHBACKCOMMENT: tNode = curNode; curNode = curNode; do { curNode = treeLast(curNode); } while (curNode != tNode && !getprop(curNode, t_Comment)); step(curNode, &theBoard); break; case C_UPFORK: while (curNode->parent) { curNode = curNode->parent; if (treeCountSiblings(curNode) > 1) break; } step(curNode, &theBoard); break; case C_DOWNFORK: { while (curNode->child) { curNode = treeDown(curNode); if (treeCountSiblings(curNode) > 1) break; } step(curNode, &theBoard); } break; case C_END: while (curNode->child) { curNode = treeDown(curNode); } step(curNode, &theBoard); break; case C_BEGINNING: curNode = root; step(curNode, &theBoard); break; case C_SCORE: doScore(&theBoard, curNode); break; case C_GOTO: { char buf[7]; nodep new; if ((*io->queryStr) ("Move to node # ?", buf, 5)) { searchNodeNum = atoi(buf); if (searchNodeNum == 0 && strcmp(buf, "0")) searchNodeNum = -1; if (searchNodeNum >= 0) { if (new = search(root)) { curNode = new; step(curNode, &theBoard); (*io->notifyClear) (); } else { (*io->notifyClear) (); (*io->notifyError) ("Node not found."); } } } } break; case C_QUIT: if (okExit(root)) quitflg++; break; case C_WRITE: { char filename[50]; if ((*io->queryStr) ("Save name? ", filename, 48)) { if (!strcmp("*", filename)) { if (!writeTree(name_buf, root)) madechanges = 0; } else { if (!writeTree(filename, root)) madechanges = 0; } } } break; case C_SAVESHORT: saveShort = !saveShort; break; case C_CURLEFT: xcur = (xcur - 1 + boardsize) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_CURRIGHT: xcur = (xcur + 1) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_CURUP: ycur = (ycur - 1 + boardsize) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_CURDOWN: ycur = (ycur + 1) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_UPLEFT: ycur = (ycur - 1 + boardsize) % boardsize; xcur = (xcur - 1 + boardsize) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_UPRIGHT: xcur = (xcur + 1) % boardsize; ycur = (ycur - 1 + boardsize) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_DOWNLEFT: xcur = (xcur - 1 + boardsize) % boardsize; ycur = (ycur + 1) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; case C_DOWNRIGHT: xcur = (xcur + 1) % boardsize; ycur = (ycur + 1) % boardsize; (*io->setCursor) (xcur, ycur); (*io->refreshIO) (); break; } } } SHAR_EOF fi if test -f 'edit.c' then echo shar: "will not over-write existing file 'edit.c'" else cat << \SHAR_EOF > 'edit.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" int first; nodep buffer = 0; FUNCTION void writeStrEscaped(output, s) FILE *output; char *s; { while (*s) { if (*s == ')' || *s == '(' || *s == ']' || *s == '[') fputc('\\', output); fputc(*(s++), output); } } #define WRITE(short,long) if (saveShort) fputs(short,output);else fputs(long,output) static char *infoshort[] = {"PB", "BR", "PW", "WR", "GN", "EV", "RO", "DT", "PC", "TM", "RE", "GC", "SO", "US", "KM"}; static char *infolong[] = { "PlayerBlack", "BlackRank", "PlayerWhite", "WhiteRank", "GameName", "EVent", "ROund", "DaTe", "PlaCe", "TiMe", "REsult", "GameComment", "SOurce", "USer", "KoMi"}; static void writeFirst(output) FILE *output; { int p; if (saveShort) { fprintf(output, "GM[1]VW[]SZ[%d]", boardsize); if (handicap) fprintf(output, "HA[%d]", handicap); } else { fprintf(output, "GaMe[1]\nVieW[]\nSiZe[%d]\n", boardsize); if (handicap) fprintf(output, "HAndicap[%d]\n", handicap); } for (p = 0; p <= t_Komi - FIRSTINFO; p++) { if (info[p]) { WRITE(infoshort[p], infolong[p]); fputc('[', output); writeStrEscaped(output, info[p]); WRITE("]", "]\n"); } } } FUNCTION void writeNode(output, n) FILE *output; nodep n; { property *prop; char str[1445]; WRITE(";", ";\n"); if (first) { writeFirst(output); first = 0; } prop = n->p; while (prop) { switch (prop->t) { case t_AddBlack: if (writeCoordList(prop->data.stones, str)) { WRITE("AB", "AddBlack"); fputs(str, output); } break; case t_AddWhite: if (writeCoordList(prop->data.stones, str)) { WRITE("AW", "AddWhite"); fputs(str, output); } break; case t_White: if (writeCoordList(prop->data.stones, str)) { WRITE("W", "White"); fputs(str, output); } break; case t_Black: if (writeCoordList(prop->data.stones, str)) { WRITE("B", "Black"); fputs(str, output); } break; case t_AddEmpty: if (writeCoordList(prop->data.stones, str)) { WRITE("AE", "AddEmpty"); fputs(str, output); } break; case t_Mark: if (writeCoordList(prop->data.stones, str)) { WRITE("M", "Mark"); fputs(str, output); } break; case t_Letter: if (writeCoordList(prop->data.stones, str)) { WRITE("L", "Letter"); fputs(str, output); } break; case t_Name: if (strlen(prop->data.comment)) { WRITE("N[", "Name["); writeStrEscaped(output, prop->data.comment); WRITE("]", "]\n"); } break; case t_Pass: if (prop->data.player == t_Black) WRITE("B", "Black"); else WRITE("W", "White"); WRITE("[tt]", "[tt]\n"); break; case t_Player: WRITE("PL[", "PLayer["); if (prop->data.player == t_Black) fputc('B', output); else fputc('W', output); WRITE("]", "]\n"); break; case t_Comment: if (strlen(prop->data.comment)) { WRITE("C[", "Comment["); writeStrEscaped(output, prop->data.comment); WRITE("]", "]\n"); } break; } prop = prop->next; } } FUNCTION void WriteSubTree(output, root, sib) FILE *output; nodep root; int sib; { WRITE("(", "(\n"); do { if (sib && root->nextSibling) { WriteSubTree(output, root, 0); while (root->nextSibling) { root = root->nextSibling; WriteSubTree(output, root, 0); } root = NULL; } else { writeNode(output, root); root = root->child; sib = 1; } } while (root); WRITE(")", ")\n"); } FUNCTION int writeCoordList(list, str) coordList *list; char *str; { *str = 0; while (list) { sprintf(str + strlen(str), "[%c%c]", list->x + 'a', list->y + 'a'); list = list->next; } if (!(strlen(str))) return 0; if (!saveShort) strcat(str, "\n"); return 1; } FUNCTION int writeTree(name, root) char *name; nodep root; { FILE *output; if (output = fopen(name, "w")) { first = 1; WriteSubTree(output, root, 1); fclose(output); return 0; } else { (*io->notifyError) ("Error saving file."); return 1; } } static void clearSpace(prop, x, y) property *prop; int x, y; { while (prop) { switch (prop->t) { case t_AddEmpty: case t_AddBlack: case t_AddWhite: case t_Black: case t_White: case t_Mark: case t_Letter: clearCoord(x, y, &(prop->data.stones)); break; } prop = prop->next; } } FUNCTION int addMark(n, t, x, y) nodep n; Token t; int x, y; { property *prop; if (prop = getprop(n, t)) { if ((getCoord(x, y, prop->data.stones))) { clearCoord(x, y, &(prop->data.stones)); return 1; } } else { prop = (property *) malloc(sizeof(property)); if (!prop) barf("Memory allocation failure (markStone)"); prop->next = n->p; n->p = prop; prop->data.stones = 0; prop->t = t; } setCoord(x, y, &(prop->data.stones)); return 0; } FUNCTION void addStone(n, t, x, y) nodep n; Token t; int x, y; { property *prop; clearSpace(n->p, x, y); if (!(prop = getprop(n, t))) { prop = (property *) calloc(1, sizeof(property)); if (!prop) barf("Memory allocation failure (addStone)"); prop->next = n->p; n->p = prop; prop->data.stones = 0; prop->t = t; } setCoord(x, y, &(prop->data.stones)); } FUNCTION int makeMove(n, t, x, y) nodep n; Token t; int x, y; { nodep new; property *prop; int ret; ret = 0; if (!(n->p)) { new = n; ret = 1; } else { new = newNode(); if (n->child) n->child->parent = new; new->parent = n; new->child = n->child; n->child = new; } prop = (property *) calloc(1, sizeof(property)); if (!prop) barf("Memory allocation failure (makeMove)"); new->p = prop; prop->data.stones = 0; prop->t = t; setCoord(x, y, &(prop->data.stones)); return ret; } FUNCTION int passMove(n, t) nodep n; Token t; { nodep new; property *prop; int ret; ret = 0; if (!(n->p)) { new = n; ret = 1; } else { new = newNode(); if (n->child) n->child->parent = new; new->parent = n; new->child = n->child; n->child = new; } prop = (property *) calloc(1, sizeof(property)); if (!prop) barf("Memory allocation failure (passMove)"); new->p = prop; prop->data.player = t; prop->t = t_Pass; return ret; } FUNCTION void addPlayer(n, t) nodep n; Token t; { property *prop; if (!(prop = getprop(n, t_Player))) { prop = (property *) calloc(1, sizeof(property)); if (!prop) barf("Memory allocation failure (addPlayer)"); addprop(n, prop); } prop->data.player = t; prop->t = t_Player; } FUNCTION void makeVariation(n) nodep n; { nodep new, last; if (!(n->child)) { new = newNode(); new->parent = n; n->child = new; } else { new = newNode(); new->parent = n; last = treeLastSibling(n->child); last->nextSibling = new; new->lastSibling = last; } } FUNCTION void cutTree(n) nodep n; { freeNode(buffer); if (n->nextSibling) n->nextSibling->lastSibling = n->lastSibling; if (n->lastSibling) n->lastSibling->nextSibling = n->nextSibling; else if (n->parent) n->parent->child = n->nextSibling; n->nextSibling = 0; n->lastSibling = 0; buffer = n; } FUNCTION boolean pasteTree(n) nodep n; { nodep last, sib; if (buffer) { for (last = buffer; last->child; last = last->child); if (n->child) { n->child->parent = last; for (sib = n->child->nextSibling; sib; sib = sib->nextSibling) sib->parent = last; last->child = n->child; } n->child = buffer; buffer->parent = n; buffer = (nodep) 0; return true; } return false; } FUNCTION void edComment(n) nodep n; { property *prop; if (!(prop = getprop(n, t_Comment))) { prop = (property *) calloc(1, sizeof(property)); prop->t = t_Comment; prop->next = n->p; n->p = prop; } (*io->editComment) (prop->data.comment, &(prop->data.comment)); if (!(prop->data.comment)) { n->p = prop->next; free(prop); } } FUNCTION void deleteNode(n) nodep *n; { nodep last; if (!((*n)->child)) { freeProps(*n); (*n)->p = 0; } else { if ((*n)->parent && (*n)->parent->child == *n) (*n)->parent->child = (*n)->child; if ((*n)->lastSibling) { (*n)->child->lastSibling = (*n)->lastSibling; (*n)->lastSibling->nextSibling = (*n)->child; } /* new parent for all of child's sibs */ for (last = (*n)->child; last->nextSibling; last = last->nextSibling) last->parent = (*n)->parent; last->parent = (*n)->parent; /* Last of child's sibs get's to point to next sib of main node */ last->nextSibling = (*n)->nextSibling; if ((*n)->nextSibling) (*n)->nextSibling = last; last = *n; *n = (*n)->child; delNode(last); } } FUNCTION void makeName(n) nodep n; { char newname[41]; property *prop; (*io->queryStr) ("Name: ", newname, 40); if (prop = getprop(n, t_Name)) free(prop->data.comment); else { prop = (property *) calloc(1, sizeof(property)); addprop(n, prop); prop->t = t_Name; } prop->data.comment = dupStr(newname); } FUNCTION void replaceComment(n, str) nodep n; char *str; { property *prop; if (!(prop = getprop(n, t_Comment))) { prop = (property *) calloc(1, sizeof(property)); prop->t = t_Comment; prop->next = n->p; n->p = prop; } else free(prop->data.comment); prop->data.comment = dupStr(str); } SHAR_EOF fi if test -f 'format' then echo shar: "will not over-write existing file 'format'" else cat << \SHAR_EOF > 'format' #!/bin/csh -f foreach f ( $* ) indent -ndj -i3 -ip0 -npcs -cli3 -di3 -npsl -ncdb -l80 $f end SHAR_EOF chmod +x 'format' fi if test -f 'goserver.c' then echo shar: "will not over-write existing file 'goserver.c'" else cat << \SHAR_EOF > 'goserver.c' /* goserver.c * */ #include <stdio.h> #include <errno.h> #include <strings.h> #include "mgt.h" #include "advunix.h" #define BUFFSIZE 2048 #define LINESIZE 1024 typedef struct ComNode { command code; int xcur; int ycur; struct ComNode *next; } comnode; static comnode *head = NULL; static int count = 0; static int hand[9][9][2] = { { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {3,9}, {15,9}, {9,15}, {9,3}, {0,0} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} }, { {15,15}, {3,3}, {3,15}, {15,3}, {3,9}, {15,9}, {9,15}, {9,3}, {0,0} }, { {15,15}, {3,3}, {3,15}, {15,3}, {9,9}, {3,9}, {15,9}, {9,15}, {9,3} } }; static void appendnode (np) comnode *np; { register comnode *temp; if (head) { temp = head; while (temp->next) temp = temp->next; temp->next = np; } else { head = np; } } static comnode *createnode(code) command code; { register comnode *temp; temp = (comnode *) malloc(sizeof(comnode)); temp->code = code; temp->next = NULL; return temp; } static void undo() { appendnode(createnode(C_TREECUT)); count--; } static void sethandicap(num) int num; { register comnode *temp; register int i; if (num < 1 || num > 9) fatal("Handicap overflow"); count++; appendnode(createnode(C_PASSMOVE)); for (i = 0; i < num; i++){ temp = createnode(C_ADDBLACK); temp->xcur = hand[num-1][i][0]; temp->ycur = boardsize - 1 - hand[num-1][i][1]; appendnode(temp); } } static void update_handicap(num) int num; { handicap = num; } static void makemove(xpos, ypos, move, color) int xpos, ypos, move, color; { register comnode *temp; if (count != move) return; if (xpos == -1 || ypos == -1) { count++; appendnode(createnode(C_PASSMOVE)); } else { count++; temp = createnode(C_MOVE); temp->xcur = xpos - 1; temp->ycur = boardsize - ypos; appendnode(temp); } } static void score_it(xpos, ypos) int xpos, ypos; { register comnode *temp; temp = createnode(C_MOVE); temp->xcur = xpos - 1; temp->ycur = boardsize - ypos; appendnode(temp); } static void RefreshBoard() { appendnode(createnode(C_PASSMOVE)); appendnode(createnode(C_BEGINNING)); appendnode(createnode(C_TREECUT)); appendnode(createnode(C_TOGGLESTONE)); handicap = 0; count = 0; } static void StartScoring() { appendnode(createnode(C_SCORE)); } static void StopScoring() { appendnode(createnode(C_SCORE)); appendnode(createnode(C_QUIT)); } static void update_status( gameno, player2, player1, p2_captured, p1_captured, p2_sec, p1_sec, p2_byoyomi, p1_byoyomi ) int gameno, p2_captured, p1_captured, p2_sec, p1_sec, p2_byoyomi, p1_byoyomi; char *player2, *player1; { static int beenhere = FALSE; if (!beenhere || strcmp(info[t_PlayerBlack - FIRSTINFO], player2) || strcmp(info[t_PlayerWhite - FIRSTINFO], player1)) { beenhere = TRUE; free(info[t_PlayerBlack - FIRSTINFO]); free(info[t_PlayerWhite - FIRSTINFO]); info[t_PlayerBlack - FIRSTINFO] = (char *) malloc(strlen(player2) + 1); info[t_PlayerWhite - FIRSTINFO] = (char *) malloc(strlen(player1) + 1); strcpy(info[t_PlayerBlack - FIRSTINFO], player2); strcpy(info[t_PlayerWhite - FIRSTINFO], player1); RefreshBoard(); } } command goserver(curnode) nodep curnode; { int code, nread; char str[BUFFSIZE]; comnode *temp; if (!tutor && head) { switch (code = head->code) { case C_MOVE: case C_ADDBLACK: case C_ADDWHITE: xcur = head->xcur; ycur = head->ycur; default: temp = head; head = head->next; free(temp); return code; } } setblock(0, FALSE); switch(nread = read(0, str, LINESIZE)) { case -1: if (errno != EWOULDBLOCK) syserr("read"); case 0: return C_NOTHING; default: str[nread] = '\0'; preprocess(str); process_input(str); return C_NOTHING; } } preprocess(str) char *str; { static char last = '\0'; register int i; if (last == '\r') { for (i = strlen(str); i >= 0; i--) str[i+1] = str[i]; str[0] = '\r'; last = '\0'; } for (i = 0; str[i] != '\0'; i++){ if (str[i] == '\r') { if (str[i+1] == '\0') { last = '\r'; str[i] = '\0'; } else if (str[i+1] != '\n') { str[i] = '\n'; } else { str[i] = ' '; } } } } /* filter.c * S.Coffin USWAT 4/92 * * process I/O stream between user and igs */ /* Copyright (c) 1992 by Stephen Coffin. All rights reserved. * * This program is distributed in the hope that it will be useful. * Use and copying of this software and preparation of derivative works * based upon this software are permitted, so long as the following * conditions are met: * o credit to the authors is acknowledged following current * academic behavior * o no fees or compensation are charged for use, copies, or * access to this software * o this copyright notice is included intact. * This software is made available AS IS, and no warranty is made about * the software or its performance. * * Bug descriptions, use reports, comments or suggestions are welcome. * Send them to scoffin@uswest.com */ /* * Rewritten by Chien-Min Wang for xmgt */ #include "shared.h" #define EMPTY 0 #define BLACK 1 #define WHITE 2 static int observeflag = FALSE; static char infileflag = FALSE; static int dbg = 0; static int move = -1; static int gameno = -1; char player1[40], player2[40]; int p1_sec, p2_sec; int p1_captured, p2_captured; int p1_byoyomi, p2_byoyomi; /* Find the first occurrence of s2 in s1 */ char *SCstrstr( s1, s2 ) char *s1, *s2; { char c, sc; int len; if( (c = *s2++) != 0 ) { len = strlen(s2); do { do { if ((sc = *s1++) == 0) return (NULL); } while (sc != c); } while (strncmp(s1, s2, len) != 0); s1--; } return( s1 ); } /* this one parses input of interest from the comm channel, and * takes appropriate action to place stones on the board */ process_input( str ) char *str; { int i, j, len, ret, tt, t, c2; int m, code, yloc; char xloc, color; static char s[BUFFSIZE]; static int beenhere = FALSE; char *temp_str, *current_str; char p1[20], p2[20]; if( !beenhere ) { beenhere = TRUE; for( j=0; j<BUFFSIZE; ++j ) s[j] = '\0'; } if( dbg ) fprintf( stderr, "In process_input: str=>>%s<<\n", str ); for( temp_str = str ;; ) { /* find newline */ for(i=0; temp_str[i] != '\n' && temp_str[i] != '\0'; ++i ); /* no newline ..... */ if( temp_str[i] == '\0' ) { if( i > 0 ) { strcat( s, temp_str ); } /* get code */ ret = sscanf( s, "%d", &code ); /* no code, print it */ if( ret != 1 ) { fprintf( stderr, "%s", s ); fflush( stderr ); for( j=0; j<BUFFSIZE; ++j ) s[j] = '\0'; } return( 0 ); } if( temp_str[i] == '\n' ) { len = strlen(s); strncat( s, temp_str, i ); s[i+len+1] = '\0'; /* get code */ ret = sscanf( s, "%d", &code ); /* no code, print it */ if( ret != 1 ) { fprintf( stderr, "%s\n", s ); fflush( stderr ); } else { /* find space */ for(j=0; s[j] != ' ' && s[j] != '\0'; ++j ); if( s[j] == ' ' ) current_str = &s[++j]; else current_str = &s[j]; switch( code ) { case HELP: /* has a "File" after code */ case THIST: case STORED: case INFO: case MESSAGE: /* scoring done under "INFO" msg */ if( observeflag == SCORING ) { ret = sscanf( current_str, "Removing @ %c%d", &xloc, &yloc ); if( ret == 2 ) { xloc = xloc - 'A' + 1; if( xloc > 8 ) --xloc; score_it( xloc, yloc ); } } if( strncmp( current_str, "File", 4 ) == 0 ) { fprintf( stderr, "%s\n", ¤t_str[4] ); if( infileflag ) infileflag = FALSE; else infileflag = TRUE; } else fprintf( stderr, "%s\n", current_str ); fflush( stderr ); break; case UNDO: /* undo */ fprintf( stderr, "\n%s\n", current_str ); fflush( stderr ); undo(); break; case MOVE: /* a move */ /* game number? */ ret = sscanf( current_str, "Game %d: %s (%d %d %d) vs %s (%d %d %d)", &t, player1, &p1_captured, &p1_sec, &p1_byoyomi, player2, &p2_captured, &p2_sec, &p2_byoyomi ); if( ret == 9 ) { if( t != gameno ) { gameno = t; fprintf( stderr, "LOCAL: Changing game number to %d\n", gameno ); } update_status( gameno, player2, player1, p2_captured, p1_captured, p2_sec, p1_sec, p2_byoyomi, p1_byoyomi ); fprintf( stderr, "%s\n", current_str ); fflush( stderr ); } /* handicap? */ ret = sscanf( current_str, "%d(%c): Handicap %d", &m, &color, &tt ); if( ret == 3 ) { fprintf( stderr, "Handicap %d\n", tt ); handicap = tt; sethandicap( tt ); update_handicap( handicap ); goto done; } /* its a move? */ ret = sscanf( current_str, "%d(%c): %c%d", &m, &color, &xloc, &yloc ); if( ret == 4 ) { move = m; if( dbg ) { fprintf( stderr, "Move=%d, color=%c, xloc=%c, yloc=%d\n", move, color, xloc, yloc ); } ret = xloc - 'A' + 1; if (ret > 8 ) --ret; if( color == 'W' ) makemove( ret, yloc, move, WHITE); else if( color == 'B' ) makemove( ret, yloc, move, BLACK); fprintf( stderr, "%s\n", current_str ); fflush( stderr ); } /* its a pass ?? */ else if( SCstrstr( current_str, "Pass" ) != NULL ) { move = m; makemove( (-1), (-1), move, EMPTY); fprintf( stderr, "%s\n", current_str ); fflush( stderr ); } done: break; case PROMPT: /* prompt */ sscanf( current_str, "%d", &c2 ); switch( c2 ) { case LOGON: fprintf( stderr, "Login: " ); break; case PASSWORD: fprintf( stderr, "Password: " ); break; case PASSWD_NEW: fprintf( stderr, "New Password: " ); break; case PASSWD_CONFIRM: fprintf( stderr, "Re-enter Password: " ); break; case WAITING: fprintf( stderr, "igs> " ); observeflag = FALSE; break; case PLAYING: /* refresh board if just start playing */ if( observeflag != PLAYING ) RefreshBoard(); fprintf( stderr, "igs [p%d]> ", gameno ); observeflag = PLAYING; break; case SCORING: if( observeflag != SCORING ) StartScoring(); fprintf( stderr, "igs [s%d]> ", gameno ); observeflag = SCORING; break; case OBSERVING: /* refresh board if just start observing */ if( observeflag != OBSERVING ) RefreshBoard(); fprintf( stderr, "igs [o%d]> ", gameno ); observeflag = OBSERVING; break; default: fprintf( stderr, "%s\n", current_str ); observeflag = FALSE; break; } fflush( stderr ); break; case SCORE: if( observeflag == SCORING ) StopScoring(); case LOOK_M: case STATUS: case UNKNOWN: /* strip the code from these, but */ case BOARD: /* otherwise pass them untouched */ case DOWN: case ERROR: case FIL: case GAMES: case LAST: case KIBITZ: case LOAD: case OBSERVE: case REFRESH: case SAVED: case SAY: case SHOUT: case TELL: case TRANS: case SHOW: /* what is this? */ case TIM: case WHO: if( strncmp( current_str, "File", 4 ) == 0 ) { fprintf( stderr, "%s\n", ¤t_str[4] ); if( infileflag ) infileflag = FALSE; else infileflag = TRUE; } else fprintf( stderr, "%s\n", current_str ); fflush( stderr ); break; case BEEP: if( current_str[0] == 0x07 ) { fprintf( stderr, "\007" ); current_str += 2; } fprintf( stderr, "%s\n", current_str ); fflush( stderr ); break; default: /* print code if it is unexpected */ fprintf( stderr, "%d %s\n", code, current_str ); fflush( stderr ); break; } } /* reset active string */ for( j=0; j<BUFFSIZE; ++j ) s[j] = '\0'; temp_str = &temp_str[i+1]; continue; } } } SHAR_EOF fi if test -f 'help.c' then echo shar: "will not over-write existing file 'help.c'" else cat << \SHAR_EOF > 'help.c' /* "mgt" Copyright (c) 1991 Shodan */ /* Short help strings. Don't make any of these longer than the longest one * already present */ char *shortHelpStr[] = { "Quit mgt (turn off help to quit)", "Move forward", "Move backward", "Next node", "Previous node", "End of the current variation", "Beginning of file", "Next comment", "Previous comment", "Next variation branch", "Last variation branch", "Jump to a specific node number", "Write Smart-Go file", "Set black stone", "Set white stone", "Make variation", "Cut tree into buffer", "Add letter", "Add mark", "Load new file", "Paste buffer in", "Edit comment", "Delete current node", "Name the current node", "Score the game", "Pass move", "Other player's turn (permanent)", "Toggle stone", "Reverse through files", "Forward through files", "Redraw screen", "Toggle save format", "Toggle tutor mode", "Save screen image", "Show game info", "Make a move", "Cursor down left", "Cursor down", "Cursor down right", "Cursor left", "Cursor right", "Cursor up left", "Cursor up", "Cursor up right", "___last command marker___"}; char *longHelpStr[] = { "I think this token has two purposes. One is to quit out of xmgt, the other is to quit scoring. You must turn off help to quit mgt :) :).", " Step down the game tree to the next move. Stop at the end of a variation and do not visit other variations.", "Move back up the game tree (previous move) -- the opposite of \",\".", "Go to the next node using a tree traversal which will visit all nodes. Sometimes the order of traversal can be confusing.", "Go to the previous node -- the opposite of \".\" forward movement.", "End of the current variation", "Beginning of file, beginning of game tree.", "Does \".\" until a node with a comment it reached.", "Does \",\" until a node with a comment it reached.", "Move forward until there is a variation branch in the game tree.", "Move backwards until there is a variation branch in the game tree.", "Goes to a numbered node. You will be prompted with a dialog box, enter the node number in the dialog box. Make sure your cursor is in the text box.", "Write out Smart-Go file. Will prompt for a filename. The path to the file is in the upper text box, the file name should be entered on the lower text box. Becarefull in the file dilog, when one hits return it is becomes part of the file name.", "Set a black stone on the board. If you click to select a point (a square box will appear) this command will place a stone on that point. This command has no regaurd for whose turn it is. This command is a toggle, selecting a point with a black stone will erase that stone, selecting a point with a white stone will place a black stone on the board.", "Set a white stone on the board. If you click to select a point (a square box will appear) this command will place a stone on that point. This command has no regaurd for whose turn it is. This command is a toggle, selecting a point with a white stone will erase that stone, selecting a point with a black stone will place a white stone on the board.", "Create a variation below the current node. The variation will initially contain a null node. You must move to that variation to make a move in it. If the \"v\" command is invoked at a node which is at the end of a variation, variation \"Var. 0\" is created with a null node. Subsequent invocations of the \"v\" command will create the \"Var. 1\", \"Var. 2\"... variations.", "Cut tree. Moves the current node and everything below it to a temporary holding buffer. (Moves your location back to the parent of the node you are one when you invoke it.)", "Places a letter on the selected point. The letters start at \"a\".", "Places a mark on the selected point. The mark is a diamond shape.", "Load new file", "Paste tree. Pastes the temporary holding buffer in after the current node. Usually the opposite of cutting the tree.", "Edits the comment. A dialog box will come up asking you if the chages are ok. You are to edit the comment, as you wish, and then click \"confirm\" to keep the comment, or \"cancel\" to revert back to the original.", "Delete node. Deletes the current node, replacing it with its child. If the current node has no child, then clear the proper- ties of the current node.", "Name the current node. You will be prompted for the name.", "Score the game. After selecting this, move the cursor around and remove the dead groups with 0 or space. You can undo one (and only one) kill with the u key. Pressing return will score the game and print the (Japanese) score in the comment area. If you missed some dead groups, continue removing them. Press q when you wish to exit scoring mode. You will be prompted to either keep the score information as a comment for the current node or restore the old comment", "Select \"Pass\" as a move.", "Other player. Changes whose turn it is, adding a token in the game tree to force the change whenever this node is visited. If the player is forced by such a token, the current player turn is indicated by } { characters on the lower right.", "Toggle stone color. Changes whose turn it is without adding any tokens in the game tree. This will not work if the game tree has a PLayer token (generated by the o key) at the current node.", "Load previous file. (Reverse through the file list)", "Load next file. (Forward through the file list", "Redraw screen, not in xmgt", "Toggle save format. Has something to do with mailgo, I believe. It should be in mgtdoc.asc -- sigh", "Toggle tutor mode -- could not find this easily -- sigh, but has something to do with making a move.", "Prompts for a file, then writes an ascii board out. Becarefull in the file dilog, when one hits return it is becomes part of the file name.", "Show game info -- -- could not find this easily -- sigh", "Make a move. The current player turn is indicated by the > < around the captured stones on the lower right. Normally, this adds the move to the game tree and moves to a new node. In tutor mode, it checks the various game continuations. If one of them contains the move you made, it moves to that variation. If not, it prints an error message. The game tree cannot be modified in tutor mode.", "Cursor down left -- not in xmgt", "Cursor down -- not in xmgt", "Cursor down right -- not in xmgt", "Cursor left -- not in xmgt", "Cursor right -- not in xmgt", "Cursor up left -- not in xmgt", "Cursor up -- not in xmgt", "Cursor up right -- not in xmgt", "___last command marker___"}; SHAR_EOF fi if test -f 'imakefile' then echo shar: "will not over-write existing file 'imakefile'" else cat << \SHAR_EOF > 'imakefile' DEFINES = -DXMGT_HFS MANSUFFIX = 6 LOCAL_LIBRARIES = XawClientLibs SRCS = help.c build.c comment.c doit.c edit.c \ mgt.c parse.c play.c tree.c Board.c x11.4.c xutil.c \ advunix.c goserver.c DirMgr.c Directory.c \ FileSel.c MultiList.c RegExp.c ScrList.c OBJS = help.o build.o comment.o doit.o edit.o \ mgt.o parse.o play.o tree.o Board.o x11.4.o xutil.o \ advunix.o goserver.o DirMgr.o Directory.o \ FileSel.o MultiList.o RegExp.o ScrList.o ComplexProgramTarget(xmgt) SHAR_EOF fi if test -f 'mailgo' then echo shar: "will not over-write existing file 'mailgo'" else cat << \SHAR_EOF > 'mailgo' #!/bin/sh # # mailgo 1.641 E-mail go game management program by Adrian Mariano # 11/21/92 I place it on the public domain. Please send improvements # to me at adrian@u.washington.edu. # # Syntax: mailgo [-r] filename # mailgo -n [filename] # mailgo -c # mailgo -e filename # # Filename should contain a mailgo go game # # -r resends the file to the opponent # -n start a new game, using data in filename to get address # -c removes temporary files left when abnormally terminated # -e edits the mailgo header and/or the game record # # Invokes the game processor in the environment variable MAILGO, or attempts # to run mgt from the inherited path if MAILGO is not set. # # System V Unix users should change the assignment to the MAILER variable # from 'mail' to 'mailx' or 'elm' or some other compatible mailer. # MAILER=mail if [ $# -eq 0 ] then echo ' ' echo 'Syntax: mailgo [-r] filename' echo ' mailgo -n [filename]' echo ' mailgo -c ' echo ' mailgo -e filename' echo ' ' echo 'Mailgo is a program to manage email go games.' echo 'Filename should contain a mailgo go game' echo ' ' echo ' -r resends the file to the opponent' echo ' -n start a new game, using data in filename to get address' echo ' -c removes temporary files left when abnormally terminated' echo ' -e edits the mailgo header and/or the game record' echo ' ' exit fi case $1 in -c) if [ $# -ne 1 ] then echo Wrong number of parameters exit else rm -f MailGo* MailFile* MailOut* exit fi;; -r) if [ $# != 2 ] then echo Wrong number of parameters exit fi if grep "\---GoGaMeEnD---" $2 >/dev/null 2>&1 then name=`sed -n '2,5s/TO: //p' $2` hisfile=`sed -n '2,5s/TOFILE: //p' $2` echo Remailing response to $name, $hisfile $MAILER -s "Remailed Go Game: $hisfile" $name < $2 exit else echo Invalid input file $2 exit fi;; -e) if [ $# -ne 2 ] then echo Wrong number of parameters exit fi if [ ! -s $2 ] then echo File $2 not found. exit fi sed -n '/---GoGaMeStArT---/,/---GoGaMeEnD---/{s/---GoGaMe.*---// p }' $2 > MailGo$$ if [ ! -s MailGo$$ ] then echo Invalid input file $2 exit fi opponent=`sed -n '2,5s/TO: //p' MailGo$$` echo To address: $opponent echo -n "new address, <ret> for no change: " read res if [ $res ] then opponent=$res fi hisfile=`sed -n '2,5s/TOFILE: //p' MailGo$$` echo To game file: $hisfile echo -n "new file name, <ret> for no change: " read res if [ $res ] then hisfile=$res fi me=`sed -n '2,5s/FROM: //p' MailGo$$` echo From address: $me echo -n "new address, <ret> for no change: " read res if [ $res ] then me=$res fi myfile=`sed -n '2,5s/FROMFILE: //p' MailGo$$` echo From game file: $myfile echo -n "new file name, <ret> for no change: " read res if [ $res ] then myfile=$res fi if sed -n 6,7p MailGo$$ | grep FORMAT > /dev/null 2>&1 then format=`sed -n '6,7s/FORMAT: //p' MailGo$$` if [ ! \( $format = 'L' -o $format = 'E' \) ] then format='S' fi else format='L' fi echo Old game record format: $format echo -n "New game record format (Long/Short/Extrashort): " read res case $res in L | l) format='L' ;; E | e) format='E' ;; S | s) format='S' ;; *) ;; esac case $format in L) sflag='';; *) sflag=-s;; esac if ${MAILGO-mgt} $sflag -m MailOut$$ MailGo$$ then if [ -s MailOut$$ ] then echo >> MailOut$$ cat <<END_END > MailFile$$ ---GoGaMeStArT--- TO: $opponent TOFILE: $hisfile FROM: $me FROMFILE: $myfile FORMAT: $format END_END if [ $format = 'S' ] then sed 's/\(;[BC]\[\)/\ \1/g' MailOut$$ >>MailFile$$ else cat MailOut$$ >> MailFile$$ fi echo >> MailFile$$ echo "---GoGaMeEnD---" >> MailFile$$ else echo -n "---GoGaMeStArT---" > MailFile$$ sed "s/TO:.*/TO: $opponent/ s/TOFILE:.*/TOFILE: $hisfile/ s/FROM:.*/FROM: $me/ s/FROMFILE:.*/FROMFILE: $myfile/ s/FORMAT:.*/FORMAT: $format/" MailGo$$ >> MailFile$$ echo "---GoGaMeEnD---" >> MailFile$$ echo -n "empty mgt file" exit fi else echo -n "---GoGaMeStArT---" > MailFile$$ sed "s/TO:.*/TO: $opponent/ s/TOFILE:.*/TOFILE: $hisfile/ s/FROM:.*/FROM: $me/ s/FROMFILE:.*/FROMFILE: $myfile/ s/FORMAT:.*/FORMAT: $format/" MailGo$$ >> MailFile$$ echo "---GoGaMeEnD---" >> MailFile$$ echo "No move made, or mgt error" fi rm -f MailGo$$ MailOut$$ echo -n "Do you wish to keep updates (y/N)? " read res case $res in Y | y) cat MailFile$$ > $2 echo Updates saved to: $2 rm -f MailFile$$ exit;; *) echo NOT keeping updates. rm -f MailFile$$ exit;; esac ;; -n) if [ $# -gt 2 ] then echo Wrong number of parameters exit fi if [ $# -eq 2 ] then if [ ! -s $2 ] then echo File $2 not found. exit fi opponent=`sed -n '2,5s/TO: //p' $2` echo Opponent address: $opponent hisfile=`sed -n '2,5s/TOFILE: //p' $2` echo His game file: $hisfile me=`sed -n '2,5s/FROM: //p' $2` echo Your address: $me myfile=`sed -n '2,5s/FROMFILE: //p' $2` echo Your game file: $myfile else echo -n "Opponent address: " read opponent echo -n "Opponent game filename: " read hisfile echo -n "Your address: " read me echo -n "Your game filename: " read myfile fi echo -n "Black player name: " read bpname echo -n " rank: " read bprank echo -n "White player name: " read wpname echo -n " rank: " read wprank echo -n "Board size (return for 19): " read bsize if [ "$bsize" -lt 7 -o "$bsize" -gt 19 ] then bsize=19 fi echo -n "Handicap: " read handicap echo -n "Komi: " read komi echo -n "Game record format (Long/Short/Extrashort): " read format case $format in L | l) format='L' ;; E | e) format='E' ;; *) format='S' ;; esac started=`date|awk '{print $3, $2, $6}'` if grep "W\[\]" $myfile >/dev/null 2>&1 then echo -n "File $myfile contains game possibly in progress. Clobber (y/N)? " read res case $res in Y | y) ;; *) echo -n "Your game filename: " read myfile;; esac fi cat <<END_END >$myfile ---GoGaMeStArT--- FROM: $me FROMFILE: $myfile TO: $opponent TOFILE: $hisfile NEWGAME FORMAT: $format END_END cat <<END_END > MailGo$$ ( ; GaMe[1] VieW[] SiZe[$bsize] Comment[Black: $bpname, $bprank White: $wpname, $wprank `if [ "$handicap" ] ; then echo "Handicap: $handicap" ; fi` `if [ "$komi" ] ; then echo "Komi: $komi" ; fi` Started: $started] PB[$bpname] BR[$bprank] PW[$wpname] WR[$wprank] `if [ "$komi" ] ; then echo KoMi[$komi] ; fi` DaTe[$started] ` case $bsize.$handicap in 19.2) echo "PL[W]HA[2]AB[dp][pd]" ;; 19.3) echo "PL[W]HA[3]AB[dp][pd][pp]" ;; 19.4) echo "PL[W]HA[4]AB[dd][dp][pd][pp]" ;; 19.5) echo "PL[W]HA[5]AB[dd][dp][jj][pd][pp]" ;; 19.6) echo "PL[W]HA[6]AB[dd][dj][dp][pd][pj][pp]" ;; 19.7) echo "PL[W]HA[7]AB[dd][dj][dp][jj][pd][pj][pp]" ;; 19.8) echo "PL[W]HA[8]AB[dd][dj][dp][jd][jp][pd][pj][pp]" ;; 19.9) echo "PL[W]HA[9]AB[dd][dj][dp][jd][jj][jp][pd][pj][pp]" ;; 13.2) echo "PL[W]HA[2]AB[dj][jd]" ;; 13.3) echo "PL[W]HA[3]AB[dj][jd][jj]" ;; 13.4) echo "PL[W]HA[4]AB[dd][dj][jd][jj]" ;; 13.5) echo "PL[W]HA[5]AB[dd][dj][gg][jd][jj]" ;; 9.2) echo "PL[W]HA[2]AB[cg][gc]" ;; 9.3) echo "PL[W]HA[3]AB[cg][gc][gg]" ;; 9.4) echo "PL[W]HA[4]AB[cc][cg][gc][gg]" ;; esac` ) END_END case $format in L) sflag='';; *) sflag=-s;; esac if ${MAILGO-mgt} $sflag -m MailOut$$ MailGo$$ then if [ -s MailOut$$ ] then cat MailOut$$ >>$myfile else cat MailGo$$ >>$myfile fi else echo -n "No move made, or mgt error. Send anyway (y/N)? " read res case $res in Y | y) cat MailGo$$ >>$myfile;; *) echo NOT mailing new game. rm -f MailGo$$ MailOut$$ exit;; esac fi rm -f MailOut$$ MailGo$$ echo Mailing new game to $opponent, $hisfile echo >> $myfile echo "---GoGaMeEnD---" >> $myfile $MAILER -s "New Go Game: $hisfile" $opponent <$myfile exit ;; esac retty='' if [ $# -ne 1 ] then echo Wrong number of parameters exit fi if [ $1 = -- ] then cat > /tmp/mailgo$$ set /tmp/mailgo$$ retty='</dev/tty' elif [ ! -s $1 ] then echo File $1 not found exit fi sed -n '/---GoGaMeStArT---/,/---GoGaMeEnD---/{s/---GoGaMe.*---// p }' $1 > MailGo$$ if [ ! -s MailGo$$ ] then echo Invalid input file $1 exit fi eval `sed -n '/---GoGaMeStArT---/,/(/{ s/^TOFILE: /fileout=/p s/^FROMFILE: /hisfile=/p s/^FORMAT: /format=/p s/^TO: /me=/p s/^FROM: /name=/p s/^NEWGAME/newgame=1/p }' $1` if [ -z "$format" ] then format=L elif [ "$format" != L -a "$format" != E ] then format=S fi case $format in L) sflag='';; *) sflag='-s';; esac if eval ${MAILGO-mgt} $sflag -m MailOut$$ MailGo$$ $retty then echo >> MailOut$$ if [ "$newgame" = 1 -a -s $fileout ] then echo -n "File $fileout exists. Clobber (y/N)? " read res case $res in Y | y) rm -f $fileout ;; *) echo -n "Output filename: " read fileout ;; esac fi cat <<EOF > MailFile$$ ---GoGaMeStArT--- TO: $name TOFILE: $hisfile FROM: $me FROMFILE: $fileout FORMAT: $format EOF case $format in S) sed 's/\(;[BC]\[\)/\ \1/g' MailOut$$ >>MailFile$$;; *) cat MailOut$$ >>MailFile$$;; esac echo "---GoGaMeEnD---" >> MailFile$$ echo Mailing response to $name, $hisfile $MAILER -s "Go Game: $hisfile" $name < MailFile$$ rm -f MailGo$$ MailOut$$ $1 if grep "\---GoGaMeEnD---" $fileout > /dev/null 2>&1 || [ ! -s $fileout ] then mv MailFile$$ $fileout else echo Save file $fileout doesn\'t look like a mailgo file. echo "Overwrite it anyway (y/N)?" read res case $res in y | Y) mv -f MailFile$$ $fileout;; *) echo Game record left in MailFile$$;; esac fi else echo No move made, or mgt error. NOT mailing response. rm -f MailGo$$ MailOut$$ fi SHAR_EOF chmod +x 'mailgo' fi if test -f 'mailgo.6' then echo shar: "will not over-write existing file 'mailgo.6'" else cat << \SHAR_EOF > 'mailgo.6' .TH MAILGO 6 "21 September 1992" .SH NAME mailgo - shell script for using mgt to automate email go games .SH SYNOPSIS .B mailgo [\-r] [\-n] [\-c] [\-e] [filename] .SH DESCRIPTION .B mailgo helps manage email games by processing Smart-Go game records received by mail, invoking mgt, and automatically sending your next move back. .LP Invoking .B mailgo with no flags instructs the program to search the specified file for a go game, ignoring mail headers or other such garbage. .B mailgo will invoke the game processor specified in the environment variable MAILGO or of this variable is undefined, will attempt to run .B mgt from the inherited path. .LP If your opponent loses your move, you can resend the game with the \-r switch. .LP To start a new game, use the \-n switch. Without a file, you will be prompted for your address, your opponent's address, and the filename for both your and your opponent's local game record. The game processor will then be invoked for you to make the first move. If a filename is specified, the address and filename data is taken from that file. .LP The \-c switch causes the program to delete any extraneous files it might have created during a previous run which was abnormally terminated. .LP To edit the mailgo headers (including mail addresses, file names and game record format) or the game record, use the \-e switch with the file name of the mailgo file you wish to edit. The file may be a saved mailgo mail message or a processed mailgo game file. The \-e option will not mail changes because of the possibility of confusing addresses. To mail edited files, use 'mailgo <file>' for edited mail messages and 'mailgo -r <file>' for edited files which have been previously processed by .B mailgo. .LP .B mailgo also supports go board sizes of 9x9, 13x13 and 19x19. Handicaps maybe set to values of 2-4 for 9x9 games, 2-5 for 13x13 games and 2-9 for 19x19 games. Any other board size or handicap must be set behind .B mailgo 's back. .SH FILE FORMAT .LP .sp .if Leading garbage ignored ---GoGaMeStArT--- TO: opponent@hissite TOFILE: his_game_record FROM: me@mysite FROMFILE: my_game_record FORMAT: format_code ( Smart\-Go game data ) ---GoGaMeEnD--- Trailing garbage ignored .fi .LP The game data file contains a leading tag to indicate the start of the data. It contains both addresses, as should be used to mail the game files, and it contains the files to store the games in. In the example above, you are playing opponent@hissite, and the game is being stored in my_game_record. .LP The file format used can be either long, short, or extrashort indicated by L, S, and E respectively. The long format uses the full size Smart-Go file saved with no options from mgt. The extrashort format uses mgt with the \-s option to save short format files. This format may cause problems for some mailers, however, because the lines will grow longer than 512 bytes. In any game record format, if very long comments are created, there is a danger of causing mailer problems. The short format is similar to the extrashort format but has extra newlines inserted. The short format is the default when selecting format from the prompt, but the long format is the default if a file contains no FORMAT line. When .B mailgo is used normally, the file specified on the command line is removed at successful completion, and the new game is saved to the file specified in the received game record. If the destination file does not look like a mailgo file, .B mailgo will query for confirmation. .SH FILES mgt .LP Smart-Go.def, the Smart\-Go format definition. .sp .SH BUGS .LP .B mailgo now handles the case where you attempt to start a new game, but are not the first player to make a real move. If after the first move you have a reason to convince mgt that you have changed the game record without really changing anything, you should enter and exit the comment editor. .fi .sp .SH AUTHOR Adrian Mariano (adrian@u.washington.edu) SHAR_EOF fi if test -f 'mgt.6' then echo shar: "will not over-write existing file 'mgt.6'" else cat << \SHAR_EOF > 'mgt.6' .TH MGT 6 "21 September 1992" .SH NAME mgt - game record display/editor for the oriental game of go .SH SYNOPSIS .B mgt [\-m filename] [\-s] [-t] [files] .SH DESCRIPTION Go is an ancient oriental strategy game based on the capturing of territory. The players alternate putting stones on the board, trying to surround as many empty intersections as possible. .LP .B Mgt allows the user to examine Go game tree files created through the Macintosh(tm) programs .B Smart-Go (tm) or .B Go Explorer (tm). .B Mgt also has basic Go game tree editing capabilities and may be used to create or edit game tree files. The on\-line material provided by a rather extensive and growing database allows many hours of instructional enjoyment of various studies and tutorials concerning the game of Go. .LP .B Mailgo is a utility which manages E-mail Go games using .B mgt as the Go board editor. It is included in the .B mgt package. .LP The .B mgt program was originally developed to be a companion for the series, "From My Go Teacher", archived at scam.berkeley.edu and ftp.u.washington.edu for ftp. Also available is the Internet GO Board communications program, 'go', also by Greg Hale, which connects up two terminals in real\-time anywhere in the world. .SH COMMAND LINE OPTIONS .TP 8 .B \-m filename Invoke a set of options used by the .B mailgo program for managing email games. If a filename is specified for loading (see below), the game record is loaded, and .B mgt automatically moves to the end of the main variation of the game record. The game can be modified without confirmation. If the game record has been modified, it will be automatically saved, on exit, to the filename specified after the \-m and .B mgt will return success (zero). If the game record has not been modified, or has not been allowed to be saved, then .B mgt will return failure (nonzero). .LP .TP 8 .B \-s Change save format used to write save files. The default save format is the long format Smart\-Go file. Using this option results in short format Smart\-Go files. .LP .TP 8 .B \-t Invoke tutor mode where you select variations by playing on the board. The key for making a move has special behavior in this mode. See the section on the "space or 0" keyboard command for a description. .LP .TP 8 .B files These are the files to be loaded. The Unix and IBM version support wildcards. If no file is specified, .B mgt loads a blank board. If you attempt to modify a file that was loaded, .B mgt will prompt for confirmation the first time. .LP .SH OPERATION .B Mgt can be used to view and edit game records, or as an electronic game board for a two person game. There are many keyboard commands which execute the various editing and display functions. .LP .TP 8 > Step down the game tree to the next move. Stop at the end of a variation and do not visit other variations. .LP .TP 8 < Move back up the game tree. (Previous move) .LP .TP 8 . Go to the next node using a tree traversal which will visit all nodes. Sometimes the order of traversal can be confusing. .LP .TP 8 , Go to the previous node -- the opposite of "." forward movement. .LP .TP 8 e Go to end of the current variation. .LP .TP 8 b Go to beginning of the game tree. .LP .TP 8 } Go forward like the "." command until a comment. .LP .TP 8 { Go backwards like the "," command until a comment. .LP .TP 8 g Go to a specified node. Type in the desired node number. .LP .TP 8 ] Move forward until there is a variation branch in the game tree. .LP .TP 8 [ Move backwards until there is a variation branch in the game tree. .LP .TP 8 k and i Scroll the game tree variation window up and down. A \- at the top of the variation window, and a + at the bottom indicate that more variations are available. .LP .TP 8 j and u Scroll comment window up and down. A \- at the top of the comment, and a + at the bottom indicate that more comments are available. .LP .TP 8 # Load new file. Will prompt for confirmation if the current file has been modified. .LP .TP 8 r Load previous file. (Reverse through the file list) .LP .TP 8 f Load next file. (Forward through the file list) .LP .TP 8 w Write out Smart\-Go file. Will prompt for a filename. The special filename * will save with the current name (which appears in the upper right corner). .LP .TP 8 space or 0 Make a move. The current player turn is indicated by the > < around the captured stones on the lower right. Normally, this adds the move to the game tree and moves to a new node. In tutor mode, it checks the various game continuations. If one of them contains the move you made, it moves to that variation. If not, it prints an error message. The game tree cannot be modified in tutor mode. .LP .TP 8 p Pass. Enter a pass move. .LP .TP 8 C Display the number of captured stones, in the X11R4 version. .LP .TP 8 o Other player. Changes whose turn it is, adding a token in the game tree to force the change whenever this node is visited. If the player is forced by such a token, the current player turn is indicated by } { characters on the lower right. .LP .TP 8 t Toggle stone color. Changes whose turn it is without adding any tokens in the game tree. This will not work if the game tree has a PLayer token (generated by the o key) at the current node. .LP .TP 8 z Set/unset black stones. .LP .TP 8 x Set/unset white stones. .LP .TP 8 q or ESC. Quit. q will prompt for confirmation. ESC will not prompt for confirmation. .LP .TP 8 v Create a variation below the current node. The variation will initially contain a null node. You must move to that variation to make a move in it. If the "v" command is invoked at a node which is at the end of a variation, variation "A" is created with a null node. Subsequent invocations of the "v" command will create the "B", "C"... variations. .LP .TP 8 ! Cut tree. Moves the current node and everything below it to a temporary holding buffer. (Moves your location back to the parent of the node you are one when you invoke it.) .LP .TP 8 ^ Paste tree. Pastes the temporary holding buffer in after the current node. Usually the opposite of cutting the tree. .LP .TP 8 c Edit the current comment. The editor has been modeled vaguely after emacs. That means that the editors commands are either 'control-key' or 'escape-key'. The controls are configurable through an environment variable. I will use ^key to indicate control keys, and ]key to indicate keys which should be preceeded by escape. On some terminals, instead of ESC-key, you can press Alt-key or Meta-key. (On the IBM version, you can use the Alt key) Under VMS, the ESC key does not work. VMS users may need to redefine the edit keys. Defaults are: .in +4m .ta .ta \w'delete to end of line (kill)\ \ 'u + 3m + .nf cursor up (previous line) ^P cursor down (next line) ^N page up (prev page) ]p page down (next page) ]n cursor left (back) ^B cursor right (forward) ^F begining of line ^A end of line ^E beginning of comment ]< end of comment ]> delete one character ^D delete to end of line (kill) ^K toggle insert mode ^I save comment ]z exit, don't save comment ^W .fi .in -4m Pressing c on a comment larger than the 120 lines allocated for comments will cause the extra to be lost. Also, on terminals which generate IBM PC arrow key codes, the arrow keys will correctly move the cursor within the comment editor. .LP .TP 8 d Delete node. Deletes the current node, replacing it with its child. If the current node has no child, then clear the properties of the current node. .LP .TP 8 n Name the current node. You will be prompted for the name. .LP .TP 8 s Score the game. After selecting this, move the cursor around and remove the dead groups with 0 or space. You can undo one (and only one) kill with the u key. Pressing return will score the game and print the (Japanese) score in the comment area. If you missed some dead groups, continue removing them. Press q when you wish to exit scoring mode. You will be prompted to either keep the score information as a comment for the current node or restore the old comment. .LP .TP 8 Ctrl\-I Enter info mode. In this mode, the various informational properties of the current file are displayed and may be edited. To edit an item, press the letter associated with it, and enter the new text. This letter must be entered in upper case. To see a list of letters, press ?. The comment window scrolling keys can be used to scroll the info display. The supported info properties are: Size, Handicap, playerBlack, bLackrank, playerWhite, whIterank, Gamename, Event, rouNd, Date, Place, Time, Result, gameComment, sOurce, User, Komi. The capital letters in this list indicate which letter selects that info property. .LP .TP 8 Ctrl\-T Toggle tutor mode. (See the section on space or 0 for explanation.) .LP .TP 8 Ctrl\-W Toggle the format used for writing Smart\-Go files between long and short. .LP .TP 8 Ctrl\-L Refresh the screen. .LP .TP 8 Ctrl\-F Save the current screen to a file. .LP .TP 8 ? Display a help screen. .LP .TP 8 12346789 Move the cursor around. Assumes standard numeric keypad orientation. .LP .SH ENVIRONMENT SETTINGS All of the characters used for the commands and the display are configurable via environment variables. For the ascii interface, use: .LP .sp .if n \{.nf setenv MGT '_ASCCOM:q><.,eb}{][gwzxv\\!lm#^cdn spotrfLWTFI012346789kiju& _ASCCHAR:@O:+\-.+|\-++++ _ASCINV _ASCED:PNpnBFAE<>DKIzO' (command should appear all on one line with a single space separating _ASC... from the previous string.) .fi \} .if t \{.nf setenv MGT '_ASCCOM:q><.,eb}{][gwzxv\\!lm#^cdnspotrfLWTFI012346789kiju& _ASCCHAR:@O=+\-.+|\-++++ _ASCINV _ASCED:PNpnBFAE<>DKIzW' .fi .in +.25i (command should appear all on one line with a single space separating _ASC... from the previous string.) .in -.25i \} .LP to get the default characters. (This is csh syntax. For other shells, the syntax will be different.) Place this line in your .cshrc so the alternate characters are always in effect. .LP The _ASCCOM string allows you to change the keyboard commands. Upper case letters stand for control characters. .LP The _ASCCHAR string specifies the display characters. For example, to use # for black stones, change the @ to # in the _ASCCHAR string. You need only include one of the two declarations ("_ASCCOM:" or "_ASCCHAR:") if you only want to change the commands or characters but not both. .LP To set the default display type to inverse video, use _ASCINV in the MGT environment variable. .LP To set the comment editor commands, use _ASCED in the MGT environment variable. For the _ASCED environment variable setting, control keys are specified with a capital letter, and ESC keys are anything which is not a capital letter. This is the key string for the defaults: PNpnBFAE<>DKIzO. Note that ^V, ^O, ^C and ^Z are poor characters to use for anything if you have berkeley unix because the berkeley tty drivers interpret these characters. The ^V character is the quoting character which quotes the following character. You will need to press it twice for mgt to see it. The other characters have to be quoted by first pressing ^V or mgt will not recognize your keypress. .LP In all cases, when you set your own keys, you must set all of the keys, and they must appear in the correct order. If multiple contradictory specifications occur in the MGT environment variable, the last that appear will be used by the program. Any option not specified will assume the default values identified above. .LP With the IBM version, the same effects may be achieved under DOS 4.0 or DOS 5.0 with a SET command placed in the AUTOEXEC.BAT file. Under previous DOS versions, quotes were interpreted literally and "|", ">" and "<" characters have special meanings and thus cannot be put into environment variables with the SET command. .LP Under VMS, the command is just MGT = "_ASCCHAR:..." .LP In the X11 version the environment variables are not used. I believe Xdefaults are used. I would be carfull setting the defaults you discover. .LP .LP .SH COMMENT FORMATTING Comments are expected to consist of long lines, each of which is one paragraph. A single long line will be formatted to fit the display. Line breaks will be ignored if they are preceeded by a space, but will be respected otherwise. .SH DISPLAYS All displays have in common the purpose of displaying a go tree. .LP ASCII display: .LP .sp .ft CW .nf A B C D E F G H S T +--------------- ---+ -Suppose this is the second 19|. . . @ . . . . . .|19| line of the comment. Since 18|. O O @ @ @ O . . .|18| there is some more of the 17|. @ @ O O O O . . .|17| comment above us unseen, 16|. @ O + . . . . . .|16| the - appears to the left 15|. @ O . O . . . . .|15| of 'Suppose'. 14|. . @ O . . . . . .|14| 13|. . @ . . . . . . .|13| 12|. . . . . . . . . .|12| 11|. . . . . . . . . .|11| And here, when there is 10|. . . + . . . . . .|10| more of the comment 9|. . . . . . . . . .| 9| below, the '+' 8|. . . . . . . . . .| 8|+appears to our left. 7|. . . . . . . . . .| 7| 6|. . . . . . . . . .| 6| Node #173: Name 5|. . . . . . . . . .| 5|-B: variation 1 hit 'B' to see 4|. . . + . . . . . .| 4| C: variation 2 hit 'C' 3|. . . . . . . . . .| 3| D: variation 3 etc... 2|. . . . . . . . . .| 2| E: variation 4 1|. . . . . . . . . .| 1|+F: variation 5 +--------------- ---+ ? for help read long A B C D E F G H S T Black #11 at 'D19' @: 0 > O: 0 < .fi .ft .LP The bottom line indicates that Black has just made move #11. On the bottom right, the angle brackets around the white stone indicate that it is White's turn. Above that, the word "read" indicates that the Smart\-Go file hasn't been modified, and "long" indicates that the default save format is the long format. "Read" will change to "edit" if you modify the file, and it will say "tutor" if you enter tutor mode. .LP The X version does not do a lot of the 'neat' stuff the ascii client does. There is no 'read', for example. A lot of those types of things are not documented by Adrian and are therefor hard to implement. If you wish to see the captured stones, in the board window type a 'C'. .LP .SH FILES The .B From My Go Teacher tutorial lessons, and many professional game records all available at ftp.u.washington.edu. .LP Internet go, a program to play go over internet, available on ftp.u.washington.edu. .LP Smart\-Go.def, the Smart\-Go format definition. .sp .SH BUGS .LP Comment editing is limited to 120 screen lines. .LP Most, but not all, of the Smart-Go properties are supported. .LP Send further bug reports to "adrian@u.washington.edu" or "hale@scam.Berkeley.EDU" .fi .sp .SH AUTHORS Greg Hale (hale@scam.berkeley.edu) .LP Jeff Boscole .LP Adrian Mariano (adrian@u.washington.edu) .sp .SH SEE ALSO rn rec.games.go \- a newsgroup on the game .br Graded go problems for beginners, vol 1-4, Ishi Press (Highly recommended) .br In the Beginning, Ishi Press. .br The Treasure Chest Enigma, Ishi Press. SHAR_EOF fi if test -f 'mgt.c' then echo shar: "will not over-write existing file 'mgt.c'" else cat << \SHAR_EOF > 'mgt.c' /* "mgt" Copyright (c) 1991 Shodan */ #include <signal.h> #include "mgt.h" int retVal = 0; interface *io; /* current interface routines */ int boardsize; /* global for board size */ char *info[LASTINFO - FIRSTINFO + 2]; int handicap; char *commentBuf; /* pointer to current node's comment */ extern interface asciiInterface; int prisoners[2]; FILE *input = 0; char name_buf[512]; char *files[MAX_FILES]; int filecount, currentfile; #ifdef DEBUG FILE *debug; unsigned long totalmemory; #endif #ifdef MGT_IBM extern unsigned _stklen = 32000; #endif typedef struct { char *arg; int *flag; char **str; } argType; int mailFlag = 0; int saveShort = 0; int tutor = 0; char *saveName; static argType argTable[] = { {"-m", &mailFlag, &saveName}, {"-s", &saveShort, NULL}, {"-t", &tutor, NULL} }; FUNCTION main(argc, argv) int argc; char **argv; { #ifdef DEBUG debug = fopen("debug", "w"); #endif io = &asciiInterface; input = stdin; init(argv, &argc); parseLine(argc, argv); doit(); myexit(); } FUNCTION void die() { signal(SIGINT, SIG_DFL); myexit(); } FUNCTION void myexit() { (*io->clearScreen) (); (*io->refreshIO) (); (*io->close) (); printf("Thank you for using mgt\n"); exit(retVal); } FUNCTION void openfile(f) char *f; { #ifdef MGT_LIB char game_lib[] = MGT_LIB; #endif /* MGT_LIB */ strcpy(name_buf, f); if (!(input = fopen(f, "r"))) strcpy(name_buf, ""); #ifdef MGT_LIB /* if not in local directory, try library */ if (!input) { strcpy(name_buf, game_lib); strcat(name_buf, f); input = fopen(name_buf, "r"); } #endif /* MGT_LIB */ } FUNCTION void barf(s) char *s; { int i; for (i = 24; i--;) fprintf(stderr, "\n"); fprintf(stderr, "%s\n", s); exit(1); } FUNCTION void initEnv() { extern char *getenv(); char *env; if (env = getenv("MGT")) while (*env) { while (*env && *env != '_') env++; if (*env) env++; if (*env) (*io->readEnv) (&env); } } FUNCTION void init(argv, argc) char *argv[]; int *argc; { initEnv(); (*io->open) (argv, argc); signal(SIGINT, die); readInit(); } FUNCTION void helpCommandLine(errMesg) char *errMesg; { (*io->close) (); fprintf(stderr, "\nERROR: %s\n\n", errMesg); fprintf(stderr, " MGT %s\n", VERSION); fprintf(stderr, "\nUsage: mgt [opts] [files]\n"); fprintf(stderr, "[opts] is any of:\n"); fprintf(stderr, "-m filename mail mode. Autosave on quit.\n"); fprintf(stderr, "-s use short format when saving.\n\n"); exit(2); } FUNCTION void parseLine(argc, argv) int argc; char **argv; { int i; filecount = 0; while (++argv, --argc > 0) { if (**argv != '-') { files[filecount++] = *argv; if (filecount == MAX_FILES) helpCommandLine("Too many files specified"); } else { for (i = 0; i < sizeof(argTable) / sizeof(argType); i++) if (!strcmp(argTable[i].arg, *argv)) { if (argTable[i].str) if (--argc) *(argTable[i].str) = (*++argv); else helpCommandLine("String expected on option"); (*(argTable[i].flag))--; break; } if (i == sizeof(argTable) / sizeof(argType)) helpCommandLine("Bad option"); } } if (!filecount) input = stdin; else { currentfile = 0; openfile(files[0]); if (!input) helpCommandLine("File not found"); } } SHAR_EOF fi if test -f 'mgt.h' then echo shar: "will not over-write existing file 'mgt.h'" else cat << \SHAR_EOF > 'mgt.h' /* "mgt" Copyright (c) 1991 Shodan */ #define VERSION "2.3" #ifdef DEBUG #define BUG(s) fprintf(debug,s) #else #define BUG(s) #endif #define FUNCTION #define false 0 #define true 1 #define MAX(a,b) ((a)>(b)?a:b) #define MIN(a,b) ((a)<(b)?a:b) #define MAX_FILES 200 #define MAX_LETTERS 12 #define MAXCOMMENT 4097 #define MAXCOMMENTLINES 300 #define MAXCOMMENTWIDTH 50 typedef int boolean; typedef enum { C_QUIT = 0, C_DOWN, C_UP, C_WALKDOWN, C_WALKUP, C_END, C_BEGINNING, C_SEARCHCOMMENT, C_SEARCHBACKCOMMENT, C_DOWNFORK, C_UPFORK, C_GOTO, C_WRITE, C_ADDBLACK, C_ADDWHITE, C_ADDVAR, C_TREECUT, C_ADDLETTER, C_ADDMARK, C_LOAD, C_PASTE, C_EDCOMMENT, C_DELNODE, C_ADDNAME, C_SCORE, C_PASSMOVE, C_TOPLAY, C_TOGGLESTONE, C_BACKFILE, C_NEXTFILE, C_REDRAW, C_SAVESHORT, C_TUTORSWAP, C_SAVESCREEN, C_INFO, C_MOVE, C_DOWNLEFT, C_CURDOWN, C_DOWNRIGHT, C_CURLEFT, C_CURRIGHT, C_UPLEFT, C_CURUP, C_UPRIGHT, C_LASTCOMMAND, C_UNDO } command; /* C_COMMENTSCROLLDOWN, C_COMMENTSCROLLUP, C_TREESCROLLDOWN, C_TREESCROLLUP, */ #define C_NOTHING ((command) 75) #define C_CHOSECHILD ((command) 76) #define C_NEXTCMD ((command) 127) typedef enum { t_White, t_Black, t_Open, t_Close, t_NewNode, t_Comment, t_AddWhite, t_AddBlack, t_Letter, t_Mark, t_AddEmpty, t_Name, t_Pass, t_Player, t_Size, t_Handicap, t_PlayerBlack, t_BlackRank, t_PlayerWhite, t_WhiteRank, t_GameName, t_Event, t_Round, t_Date, t_Place, t_TimeLimit, t_Result, t_GameComment, t_Source, t_User, t_Komi, t_WS, t_EOF } Token; #define FIRSTINFO ((int)t_PlayerBlack) #define LASTINFO ((int)t_User) typedef enum { P_NOTHING = 0, P_BLACK, P_WHITE, P_DAME, P_BLACKTERR, P_WHITETERR, P_CHECKED } piece; typedef piece boardType[19][19]; typedef struct { boardType b; } board, *pBoard; typedef int (*pfi) (); typedef struct { char *name; char *option; char *storage; pfi open, close, refreshIO, plotPiece, displayComment; pfi clearComment, initializeBoard, clearScreen, idle; pfi drawTree, highlightLast, readEnv, notifyMessage; pfi notifyClear, queryStr, setCursor, plotMark, plotLetter; pfi getPoint, editComment, askYN, notifyError, displayInfo; pfi getInfoToChange, editInfo; } interface, *interfaceP; typedef struct { char x, y; } coord; typedef struct coordstruct { char x, y; struct coordstruct *next; } coordList; typedef struct propertyRec { struct propertyRec *next; Token t; union { coordList *stones; char *comment; Token player; } data; } property; typedef struct noderec { property *p; int nodeNum; struct noderec *parent, *child, *nextSibling, *lastSibling; } node, *nodep; /* board coordinates used to indicate a pass */ #define PASSVAL 25 #include "proto.h" #include <stdio.h> #ifdef MGT_IBM #include <alloc.h> #endif extern char *info[LASTINFO - FIRSTINFO + 2]; extern int handicap; extern interface *io; extern int boardsize; extern int prisoners[2]; extern FILE *input; extern int xcur, ycur; extern Token curPlayer; extern int mailFlag; extern int saveShort; extern int tutor; extern char *saveName; extern int retVal; extern char name_buf[512]; extern filecount, currentfile; extern char *files[MAX_FILES]; #ifdef DEBUG extern FILE *debug; extern unsigned long totalmemory; #endif SHAR_EOF fi if test -f 'parse.c' then echo shar: "will not over-write existing file 'parse.c'" else cat << \SHAR_EOF > 'parse.c' /* "mgt" Copyright (c) 1991 Shodan */ #include <string.h> #include "mgt.h" struct { char *str; Token val; } tokens[] = { { "W", t_White }, { "B", t_Black }, { "C", t_Comment }, { "AW", t_AddWhite }, { "AB", t_AddBlack }, { "L", t_Letter }, { "AE", t_AddEmpty }, { "N", t_Name }, { "M", t_Mark }, { "SZ", t_Size }, { "GN", t_GameName }, { "GC", t_GameComment }, { "EV", t_Event }, { "RO", t_Round }, { "DT", t_Date }, { "PC", t_Place }, { "PB", t_PlayerBlack }, { "PW", t_PlayerWhite }, { "RE", t_Result }, { "US", t_User }, { "TM", t_TimeLimit }, { "SO", t_Source }, { "BR", t_BlackRank }, { "WR", t_WhiteRank }, { "HA", t_Handicap }, { "KM", t_Komi }, { "PL", t_Player } }; char buf[1028], *curin, started; FUNCTION void readInit() { int p; buf[0] = '\0'; curin = &buf[0]; started = 1; boardsize = 19; handicap = 0; for (p = 0; p <= LASTINFO - FIRSTINFO + 1; p++) { if (info[p]) free(info[p]); info[p] = 0; } } static char *readLine() { curin = &buf[0]; buf[0] = '\0'; return fgets(&buf[0], 1023, input); } static char readChar() { if (*curin) return *(curin++); curin = &buf[0]; buf[0] = '\0'; fgets(&buf[0], 1023, input); return 0; } static int getCoordStr(co) coord *co; { if (strlen(curin) < 4 && curin[strlen(curin) - 1] != '\n') { char *dest; for (dest = buf; *curin; curin++, dest++) *dest = *curin; *dest = 0; fgets(dest, 1023, input); curin = buf; } if (curin[0] == '[' && curin[1] >= 'a' && curin[1] <= 's' && curin[2] >= 'a' && curin[2] <= 's' && curin[3] == ']') { co->x = curin[1] - 'a'; co->y = curin[2] - 'a'; curin += 4; while (*curin == ' ' || *curin == '\t') curin++; if (*curin == '\n') readLine(); return 1; } else return 0; } static void getCoordList(clp) coordList **clp; { coord co; while (getCoordStr(&co)) { setCoord(co.x, co.y, clp); } } static void addPass(n, t) nodep n; Token t; { property *p; if (!(p = (property *) calloc(1, sizeof(property)))) barf("Memory allocation error (addPass)"); p->t = t_Pass; p->data.player = t; addprop(n, p); } static void doPlayer(n) nodep n; { property *p; if (curin[0] == '[' && curin[2] == ']' && (curin[1] == 'B' || curin[1] == 'W')) { p = (property *) calloc(1, sizeof(property)); if (!p) barf("Memory allocation failure (doPlayer)"); p->t = t_Player; p->data.player = curin[1] == 'B' ? t_Black : t_White; curin += 3; addprop(n, p); } } static Token tokenize() { int i, len; char buf[4]; len = 0; do { if (!*curin || *curin == '\n') { if (!readLine()) return t_EOF; } if (*curin == ')') { curin++; return t_Close; } if (*curin == '(') { curin++; return t_Open; } if (*curin == ';') { curin++; return t_NewNode; } if (*curin >= 'A' && *curin <= 'Z') buf[len++] = *curin; curin++; } while (len < 3 && *curin != '['); buf[len] = 0; if (len == 1 || len == 2) for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) if (!strcmp(buf, tokens[i].str)) return tokens[i].val; while (*curin != ']') { if (!*++curin) { if (!readLine()) return t_EOF; } } return t_WS; } static void addMoveArrayProp(t, n) Token t; nodep n; { property *p; #ifdef DEBUG totalmemory += sizeof(property); fprintf(debug, "%ld %ld\n", totalmemory, coreleft()); #endif if (!(p = getprop(n, t))) { p = (property *) calloc(1, sizeof(property)); #ifdef DEBUG totalmemory += sizeof(coordList); fprintf(debug, "%ld %ld\n", totalmemory, coreleft()); #endif if (!p) barf("Memory allocation failure (addMoveArrayProp)"); p->data.stones = 0; p->t = t; addprop(n, p); } getCoordList(&(p->data.stones)); } static void doSize() { int size; char *s, c, b[25]; s = &b[0]; readChar(); while ((c = readChar()) != ']') if (c && c != '\\') *s++ = c; *s = 0; size = atoi(b); if ((size > 1) && (size <= 19)) boardsize = size; } static void doHandicap() { int size; char *s, c, b[25]; s = &b[0]; readChar(); while ((c = readChar()) != ']') if (c && c != '\\') *s++ = c; *s = 0; size = atoi(b); if ((size > 1) && (size <= 17)) handicap = size; } static void doComment(n, t) nodep n; Token t; { char c, *s, *buffer; property *p; int space; buffer = (char *) malloc(MAXCOMMENT); p = (property *) calloc(1, sizeof(property)); if (!(p && buffer)) barf("Memory Allocation Failure (doComment)"); s = buffer; space = MAXCOMMENT - 1; readChar(); while ((c = readChar()) != ']') { if (!c && feof(input)) break; if (c == '\\') c = readChar(); if (c && space) { *s++ = c; space--; } } if (*(s - 1) == '\n') s--; *s = 0; p->t = t; p->data.comment = dupStr(buffer); addprop(n, p); free(buffer); } static void doInfo(t) Token t; { char *buffer, *s, c; int space; buffer = (char *) malloc(MAXCOMMENT); if (!buffer) barf("Memory allocation failure (doInfo)"); s = buffer; space = MAXCOMMENT - 1; readChar(); while (space && (c = readChar()) != ']') { if (c == '\\') c = readChar(); if (c) { *s++ = c; space--; } } if (*(s - 1) == '\n') s--; *s = 0; info[(int) t - FIRSTINFO] = dupStr(buffer); free(buffer); } FUNCTION void addChild(n, c) /* add child c to node n */ nodep n, c; { if (n) { if (n->child) { nodep s; s = treeLastSibling(child(n)); s->nextSibling = c; c->lastSibling = s; c->parent = n; } else { n->child = c; c->parent = n; } } } FUNCTION nodep parse(lev) int lev; { nodep r, n, new; Token t; if (started) { started = 0; while (*curin != '(') { if (!readLine()) break; } } r = n = 0; for (;;) { t = tokenize(); switch (t) { case t_Size: doSize(); break; case t_White: case t_Black: if (curin[1] == 't' && curin[2] == 't' && curin[0] == '[' && curin[3] == ']') { addPass(n, t); break; } case t_AddWhite: case t_AddBlack: case t_AddEmpty: case t_Mark: case t_Letter: if (n) addMoveArrayProp(t, n); else fprintf(stderr, "Error - property w/o node in data\n"); break; case t_Player: if (n) doPlayer(n); else fprintf(stderr, "Error - property w/o node in data\n"); break; case t_Name: case t_Comment: if (n) doComment(n, t); else fprintf(stderr, "Error - property w/o node in data\n"); break; case t_NewNode: new = newNode(); if (!r) r = new; else addChild(n, new); n = new; break; case t_Open: if (lev == 1 && !r) n = r = newNode(); if (new = parse(lev + 1)) { addChild(n, new); if (!r) r = new; } break; case t_Close: case t_EOF: return r; case t_GameName: case t_GameComment: case t_Event: case t_Round: case t_Date: case t_Place: case t_PlayerBlack: case t_PlayerWhite: case t_Result: case t_User: case t_TimeLimit: case t_Source: case t_BlackRank: case t_WhiteRank: doInfo(t); break; case t_Komi:{ char *ch, *end; doInfo(t_Komi); end = ch = info[(int) t_Komi - FIRSTINFO]; while (*end) end++; for (end--; *end == '0' && (end != ch); end--); *++end = 0; } break; case t_Handicap: doHandicap(); break; default: break; } } } SHAR_EOF fi if test -f 'play.c' then echo shar: "will not over-write existing file 'play.c'" else cat << \SHAR_EOF > 'play.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" #include <string.h> #include <stdio.h> /* void printboard(char *s,pBoard b) { FILE *fil; int i,j; * fil=fopen("dump","a+"); if (!fil) {printf("can't open file");getch();} * fprintf(fil,"%s\n",s); for(i=0;i<boardsize;i++){ for(j=0;j<boardsize;j++) * fputc( b->b[i][j]==P_NOTHING?'.':(b->b[i][j]==P_BLACK?'*':'O'),fil); * fputc('\n',fil); } fclose(fil); } */ FUNCTION int legal(b, n, player, i, j) pBoard b; nodep n; int i, j; Token player; { board a, copy; int same, x, y, savex, savey, savemove; boolean islegal; extern int moveNum; int savepris[2]; extern int prisoners[]; savemove = moveNum; savex = xcur; savey = ycur; savepris[0] = prisoners[0]; savepris[1] = prisoners[1]; copyBoard(b, ©); islegal = true; if (b->b[i][j] != P_NOTHING) { (*io->notifyError) ("There's already a piece there."); return false; } placeStone(©, i, j, (player == t_Black) ? P_BLACK : P_WHITE); if (!alive(©, i, j)) { (*io->notifyError) ("That move is suicide."); islegal = false; } if (islegal && (n = n->parent)) { boardClear(&a); buildTree0(n, &a); same = true; for (x = boardsize; same && x--;) for (y = boardsize; same && y--;) { same = (copy.b[x][y] == a.b[x][y]); } if (same) { (*io->notifyError) ("Can't retake the ko yet."); islegal = false; } } xcur = savex; ycur = savey; prisoners[0] = savepris[0]; moveNum = savemove; prisoners[1] = savepris[1]; return islegal; } FUNCTION boolean inRange(i, j) { return i >= 0 && i < boardsize && j >= 0 && j < boardsize; } FUNCTION boolean alive0(b, m, i, j, t) pBoard b; pBoard m; int i, j; piece t; { piece pt; pt = b->b[i][j]; if ((pt != P_NOTHING && pt != t) || m->b[i][j] != P_NOTHING) return 0; m->b[i][j] = (pt == t) ? (piece) 1 : (piece) 2; if (pt == P_NOTHING) return 1; return (j < boardsize - 1 && alive0(b, m, i, j + 1, t)) || (i < boardsize - 1 && alive0(b, m, i + 1, j, t)) || (i && alive0(b, m, i - 1, j, t)) || (j && alive0(b, m, i, j - 1, t)); } FUNCTION boolean alive(b, i, j) /* Does group at i,j have liberties? */ pBoard b; int i, j; { board m; boardClear(&m); return alive0(b, &m, i, j, b->b[i][j]); } void removeStones0(b, i, j, t) pBoard b; int i, j; piece t; { extern int prisoners[]; if (b->b[i][j] != t) return; b->b[i][j] = P_NOTHING; prisoners[(int) t - 1]++; if (j < boardsize - 1) removeStones0(b, i, j + 1, t); if (i < boardsize - 1) removeStones0(b, i + 1, j, t); if (i) removeStones0(b, i - 1, j, t); if (j) removeStones0(b, i, j - 1, t); } FUNCTION void removeStones(b, i, j) pBoard b; int i, j; { removeStones0(b, i, j, b->b[i][j]); } FUNCTION boolean tryKill(b, i, j, t) pBoard b; int i, j; piece t; { piece w; if (!inRange(i, j)) return false; w = b->b[i][j]; if (w != P_NOTHING && w != t && !alive(b, i, j)) { removeStones(b, i, j); return true; } return false; } FUNCTION void placeStone(b, i, j, t) pBoard b; int i, j; piece t; { if (inRange(i, j)) { b->b[i][j] = t; xcur = i; ycur = j; if (j) tryKill(b, i, j - 1, t); if (j < boardsize - 1) tryKill(b, i, j + 1, t); if (i) tryKill(b, i - 1, j, t); if (i < boardsize - 1) tryKill(b, i + 1, j, t); } } FUNCTION void boardSet(b, i, j, p) pBoard b; int i, j; piece p; { b->b[i][j] = p; } FUNCTION piece boardGet(b, i, j) pBoard b; int i, j; { return b->b[i][j]; } FUNCTION void boardClear(b) pBoard b; { memset((char *) (b->b), 0, 361 * sizeof(piece)); /* int i, j; for (i = boardsize; i--;) for (j = boardsize; j--;) b->b[i][j] * = P_NOTHING; */ } FUNCTION void copyBoard(a, b) pBoard a, b; { int i, j; for (i = boardsize; i--;) for (j = boardsize; j--;) b->b[i][j] = a->b[i][j]; } int look(stone, array, index, i) int stone, array[], *index, i; { if (stone == P_NOTHING) array[(*index)++] = i; else if (stone == P_BLACK) return 1; else if (stone == P_WHITE) return 2; return 0; } int fillregion(b, x, y) pBoard b; int x, y; { int goup[19], godown[19], up = 0, down = 0, found = 0, i; for (i = x; i < boardsize && b->b[i][y] == P_NOTHING; i++) { b->b[i][y] = P_CHECKED; if (y > 0) found |= look(b->b[i][y - 1], goup, &up, i); if (y < boardsize - 1) found |= look(b->b[i][y + 1], godown, &down, i); } if (i != boardsize) { if (b->b[i][y] == P_BLACK) found |= 1; if (b->b[i][y] == P_WHITE) found |= 2; } for (i = x - 1; i >= 0 && b->b[i][y] == P_NOTHING; i--) { b->b[i][y] = P_CHECKED; if (y > 0) found |= look(b->b[i][y - 1], goup, &up, i); if (y < boardsize - 1) found |= look(b->b[i][y + 1], godown, &down, i); } if (i != -1) { if (b->b[i][y] == P_BLACK) found |= 1; if (b->b[i][y] == P_WHITE) found |= 2; } while (up) found |= fillregion(b, goup[--up], y - 1); while (down) found |= fillregion(b, godown[--down], y + 1); return found; } FUNCTION void scoreBoard(b, score) pBoard b; int score[]; { int x, y, i, j, owner; piece newval; score[0] = 0; score[1] = 0; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) { owner = fillregion(b, i, j); if (!owner) owner = 3; switch (owner) { case 3: newval = P_DAME; break; case 2: newval = P_WHITETERR; break; case 1: newval = P_BLACKTERR; break; } for (x = 0; x < boardsize; x++) for (y = 0; y < boardsize; y++) if (b->b[x][y] == P_CHECKED) { b->b[x][y] = newval; if (owner != 3) score[owner - 1]++; } } } SHAR_EOF fi if test -f 'proto.h' then echo shar: "will not over-write existing file 'proto.h'" else cat << \SHAR_EOF > 'proto.h' extern void clearLast(); extern void highlightLast(); extern void doPlace(); extern void doProps(); extern void doPropComment(); extern void buildTree0(); extern void buildTree(); extern void setPiece(); extern void updateBoard(); extern char *commentGet(); /* int */ extern int commentLines(); extern void formatComment(); extern int okChange(); extern int okExit(); extern nodep search(); /* return 0 on failure */ extern void step(); extern void stepDown(); extern void doScore(); extern nodep loadFile(); extern nodep makeTutor(); extern void doit(); extern void writeStrEscaped(); extern void writeNode(); extern void WriteSubTree(); extern int writeCoordList(); extern int writeTree(); extern int addMark(); extern void addStone(); extern int makeMove(); extern int passMove(); extern void addPlayer(); extern void makeVariation(); extern void cutTree(); extern boolean pasteTree(); extern void edComment(); extern void deleteNode(); extern void makeName(); extern void replaceComment(); extern main(); extern void die(); extern void myexit(); extern void openfile(); extern void barf(); extern void initEnv(); extern void init(); extern void helpCommandLine(); extern void parseLine(); extern void readInit(); extern void addChild(); /* add child c to node n */ extern nodep parse(); extern int legal(); extern boolean inRange(); extern boolean alive0(); extern boolean alive(); /* Does group at i,j have liberties? */ extern void removeStones(); extern boolean tryKill(); extern void placeStone(); extern void boardSet(); extern piece boardGet(); extern void boardClear(); extern void copyBoard(); extern void scoreBoard(); extern boolean getCoord(); extern coordList *addCoord(); extern void setCoord(); extern void clearCoord(); extern void initNodes(); extern nodep newNode(); extern void freeNode(); extern char *dupStr(); extern void freeProps(); extern void delNode(); extern void addprop(); extern property *getprop(); extern int treeCountSiblings(); extern nodep nthChild(); /* nodep, int */ extern nodep parent(); extern nodep child(); extern nodep lastSibling(); extern nodep nextSibling(); extern nodep treeLastSibling(); extern nodep treeDown(); extern nodep treeUp(); extern nodep treeNextUp(); extern nodep treeNext(); extern nodep lastChildOfLastSibling(); extern nodep treeLast(); SHAR_EOF fi if test -f 'shared.h' then echo shar: "will not over-write existing file 'shared.h'" else cat << \SHAR_EOF > 'shared.h' /* shared.h * S.Coffin USWAT 1/93 * * bits for compatibility with the IGS * * adapted from tcasey@leo.unm.edu */ #ifndef SHARED_H #define SHARED_H #define MAX_BRD_SZ 25 typedef enum { UNKNOWN = 0, BEEP = 2, /* \7 telnet */ BOARD = 3, /* Board being drawn */ DOWN = 4, /* The server is going down */ ERROR = 5, /* An error reported */ FIL = 6, /* File being sent */ GAMES = 7, /* Games listing */ HELP = 8, /* Help file */ INFO = 9, /* Generic info */ LAST = 10, /* Last command */ KIBITZ = 11, /* Kibitz strings */ LOAD = 12, /* Loading a game */ LOOK_M = 13, /* Look */ MESSAGE = 14, /* Message lising */ MOVE = 15, /* Move #:(B) A1 */ OBSERVE = 16, /* Observe report */ PROMPT = 1, /* A Prompt (never) */ REFRESH = 17, /* Refresh of a board */ SAVED = 18, /* Stored command */ SAY = 19, /* Say string */ SCORE = 20, /* Score report */ SHOUT = 21, /* Shout string */ STATUS = 22, /* Current Game status */ STORED = 23, /* Stored games */ TELL = 24, /* Tell string */ THIST = 25, /* Thist report */ TIM = 26, /* times command */ WHO = 27, /* who command */ UNDO = 28, /* Undo report */ SHOW = 29, TRANS = 30 /* Translation info <=== last value */ } MessageType; #define LOGGEDON WAITING typedef enum { LOGON = 0, PASSWORD = 1, PASSWD_NEW = 2, PASSWD_CONFIRM = 3, REGISTER = 4, WAITING = 5, PLAYING = 6, SCORING = 7, OBSERVING = 8 } State; #define NUM_RANKS num_ranks #define NUM_SPECIAL 2 /* * verticies */ #define TOP 0 #define MID 1 #define BOT 2 #endif /* SHARED_H */ SHAR_EOF fi if test -f 'tree.c' then echo shar: "will not over-write existing file 'tree.c'" else cat << \SHAR_EOF > 'tree.c' /* "mgt" Copyright (c) 1991 Shodan */ #include "mgt.h" static int newNodeNum; FUNCTION boolean getCoord(x, y, list) int x, y; coordList *list; { for (; list; list = list->next) if (list->x == x && list->y == y) return true; return false; } FUNCTION coordList *addCoord(x, y) int x, y; { coordList *co; if (!(co = (coordList *) malloc(sizeof(coordList)))) barf("Memory allocation failure (addCoord)"); co->next = 0; co->x = x; co->y = y; return co; } FUNCTION void setCoord(x, y, startlist) int x, y; coordList **startlist; { coordList *list; if (!*startlist) *startlist = addCoord(x, y); else { for (list = *startlist; list->next; list = list->next) if (x == list->x && y == list->y) return; list->next = addCoord(x, y); } } FUNCTION void clearCoord(x, y, startlist) int x, y; coordList **startlist; { coordList *last, *list; last = 0; list = *startlist; while (list && (x != list->x || y != list->y)) { last = list; list = list->next; } if (list) { if (last) last->next = list->next; else *startlist = list->next; free(list); } } FUNCTION void initNodes() { newNodeNum = 0; } FUNCTION nodep newNode() { nodep new; #ifdef DEBUG totalmemory += sizeof(node); fprintf(debug, "%ld %ld\n", totalmemory, coreleft()); #endif new = (nodep) calloc(1, sizeof(node)); if (!new) barf("Memory allocation failure (newnode)"); new->nodeNum = newNodeNum++; return new; } FUNCTION void freeNode(n) nodep n; { if (n) { freeNode(n->nextSibling); freeNode(n->child); delNode(n); } } FUNCTION char *dupStr(s) char *s; { char *c; #ifdef DEBUG totalmemory += strlen(s) + 1; fprintf(debug, "%ld %ld\n", totalmemory, coreleft()); #endif c = (char *) malloc((unsigned) strlen(s) + 1); if (!c) barf("Memory allocation failure (dupstr)"); strcpy(c, s); return c; } FUNCTION void freeProps(n) nodep n; { property *prop, *lastprop; coordList *cl, *lastcl; prop = n->p; while (prop) { switch (prop->t) { case t_AddEmpty: case t_AddBlack: case t_AddWhite: case t_Mark: case t_Letter: case t_Black: case t_White: cl = prop->data.stones; while (cl) { lastcl = cl; cl = cl->next; free(lastcl); } break; case t_Name: case t_Comment: free(prop->data.comment); break; } lastprop = prop; prop = prop->next; free(lastprop); } } FUNCTION void delNode(n) nodep n; { freeProps(n); free(n); } FUNCTION void addprop(n, p) nodep n; property *p; { p->next = n->p; n->p = p; } FUNCTION property *getprop(n, t) nodep n; Token t; { property *p; p = n->p; while (p && p->t != t) p = p->next; return p; } FUNCTION int treeCountSiblings(n) nodep n; { int i; nodep n1; n1 = n->child; i = 0; while (n1) { n1 = n1->nextSibling; i++; } return i; } FUNCTION nodep nthChild(n, c) /* nodep, int */ nodep n; int c; { if (n->child) { n = child(n); while (c-- && n) n = nextSibling(n); } else { n = 0; } return n; } /* TREE WALK functions KEEP TRACK OF DEPTH AS WELL */ FUNCTION nodep parent(n) nodep n; { return n->parent; } FUNCTION nodep child(n) nodep n; { return n->child; } FUNCTION nodep lastSibling(n) nodep n; { return n->lastSibling; } FUNCTION nodep nextSibling(n) nodep n; { return n->nextSibling; } FUNCTION nodep treeLastSibling(n) nodep n; { while (n->nextSibling) { n = n->nextSibling; } return n; } /* go to next node down the tree. Stop if at bottom. */ FUNCTION nodep treeDown(n) nodep n; { if (n->child) { BUG("treeDown: going down\n"); return child(n); } else { BUG("treeDown: stop\n"); return n; } } /* backup, stop if at top */ FUNCTION nodep treeUp(n) nodep n; { if (n->parent) { BUG("treeUp: going up\n"); return parent(n); } else { BUG("treeUp: staying\n"); return n; } } /* go to next node backing up the tree only */ FUNCTION nodep treeNextUp(n) nodep n; { if (n->nextSibling) { BUG("nextSibling "); return nextSibling(n); } else if (n->parent) { BUG("nextup-parent "); while (n->parent && !n->nextSibling) n = parent(n); if (n->nextSibling) return nextSibling(n); else return n; } else if (n->child) { BUG("child "); return child(n); } else { BUG("current "); return n; } } /* go to next node, backup if neccessary */ FUNCTION nodep treeNext(n) nodep n; { nodep r; BUG("treeNext:"); if (n != (r = treeDown(n))) { BUG("going down "); } else { BUG("going up "); r = treeNextUp(n); } BUG("\n"); return r; } FUNCTION nodep lastChildOfLastSibling(n) nodep n; { while (n->nextSibling) n = nextSibling(n); if (n->child) return lastChildOfLastSibling(child(n)); else return n; } /* go to next node, backup if neccessary */ FUNCTION nodep treeLast(n) nodep n; { nodep r; if (n->lastSibling) { n = lastSibling(n); if (n->child) r = lastChildOfLastSibling(child(n)); else r = n; } else if (n->parent) { r = parent(n); } else if (n->child) { r = lastChildOfLastSibling(child(n)); } else { r = n; } return r; } SHAR_EOF fi if test -f 'wrapmgt.6' then echo shar: "will not over-write existing file 'wrapmgt.6'" else cat << \SHAR_EOF > 'wrapmgt.6' .TH WRAPMGT 6 "23 November 1992" .SH NAME wrapmgt - wraps long lines in Smart-Go files to make them safe to post or email .SH SYNOPSIS .B wrapmgt [nn] .SH DESCRIPTION .B Wrapmgt formats Smart-Go files as generated by .B mgt so that the lines are shorter than nn, the number specified on the command line. The default format width is 79 characters. .B Wrapmgt reads its input from stdin and writes to stdout. This means you should invoke it using I/O redirection which is done under unix and DOS with wrapmgt < infile > outfile. .LP The files are formatted in such a way that if the files are viewed in mgt after being formatted, they will look the same as the original. The new line breaks will be visible from within the editor, however. .SH AUTHOR Adrian Mariano (adrian@u.washington.edu) SHAR_EOF fi if test -f 'wrapmgt.c' then echo shar: "will not over-write existing file 'wrapmgt.c'" else cat << \SHAR_EOF > 'wrapmgt.c' #include<stdio.h> main(argc,argv) int argc; char *argv[]; { char *last,line[100]; int cur,limit; int intext,incomment; limit=79; if (argc>2){ fprintf(stderr,"Wrong number of arguments.\n\n"); exit(1); } if (argc==2){ limit=atoi(argv[1]); if (!limit){ fprintf(stderr,"Invalid limit\n\n"); exit(2); } } last=0; cur=0; intext=0; incomment=0; do{ line[cur]=getchar(); /* This next line makes the program aggressively eat up white space */ /* found outside the text sections */ if (!intext && (line[cur]==' ' || line[cur]=='\n' || line[cur]=='\r')) continue; /* These tests come first because they don't look at the current character */ /* They need to be checked before the flags (next section) are reset */ /* line breaks at spaces within comments only */ if (incomment && cur && line[cur-1]==' ') last= &line[cur]; /* line breaks at after ']' if followed by capital letter */ if (!intext && cur>2 && line[cur-1]>='A' && line[cur-1]<='Z' && line[cur-2]==']' && line[cur-3]!='\\') last= &line[cur-1]; /* These change the various flags */ /* Check for start of comment 'C[' */ if (cur && line[cur-1]=='C' && line[cur]=='[') incomment=intext=1; /* Check for start of non-comment bracketed section */ if (line[cur]=='[' && (cur==0 || line[cur-1]!='\\')) intext=1; /* check for end of bracketed sections ']' */ if (intext && line[cur]==']' && (cur==0 || line[cur-1]!='\\')) intext=incomment=0; /* This test does use current character */ /* line breaks at ';' outside of text */ if (!intext && line[cur]==';') last= &line[cur]; if (line[cur]=='\n'){ line[cur+1]=0; fputs(line,stdout); last=line; cur= -1; } cur++; if (cur>=limit && last){ char *loc,*end; for(loc=line;loc<last;loc++) putchar(*loc); putchar('\n'); loc=line; line[cur]=0; strcpy(line,last); last=0; cur=strlen(line); } }while(!feof(stdin)); line[cur]=0; fputs(line,stdout); } SHAR_EOF fi if test -f 'x11.4.c' then echo shar: "will not over-write existing file 'x11.4.c'" else cat << \SHAR_EOF > 'x11.4.c' /* x11.4.c * * Copyright (c) 1992 by Chien-Min Wang and Tim Casey. * All rights reserved. */ #include <stdio.h> #include <math.h> #include <assert.h> #include <X11/Xlib.h> #include <X11/Intrinsic.h> #include <X11/StringDefs.h> #include <X11/Shell.h> #include <X11/bitmaps/xlogo11> #include <X11/Xaw/MenuButton.h> #include <X11/Xaw/SimpleMenu.h> #include <X11/Xaw/SmeBSB.h> #include <X11/Xaw/SmeLine.h> #include <X11/Xaw/Command.h> #include <X11/Xaw/Form.h> #include <X11/Xaw/AsciiText.h> #include <X11/Xaw/Viewport.h> #include "Board.h" #include "mgt.h" #include "xutil.h" #define INDEX_TO_POS(n) (boardsize-1-(n)) #define NEXTSIBLING(n) ((n)->nextSibling) #define EMPTY_STR "" #define MAX_VARS 26 #define BUF_SIZE 200 Res reses; ResPtr resp = &reses; XtResource resources[] = { #define offset(field) XtOffset(ResPtr,field) #define DefaultFont "-misc-fixed-bold-r-*-*-13-*-*-*-*-70-*-*" #define FontWidth 7 { "commHeight", "CommHeight", XtRInt, sizeof(int), offset(comm_ht), XtRImmediate, (caddr_t) 500 }, { "commWidth", "CommWidth", XtRInt, sizeof(int), offset(comm_wd), XtRImmediate, (caddr_t) 656 }, { "noteHeight", "NoteHeight", XtRInt, sizeof(int), offset(note_ht), XtRImmediate, (caddr_t) 20 }, { "noteWidth", "NoteWidth", XtRInt, sizeof(int), offset(note_wd), XtRImmediate, (caddr_t) 674 }, { "variationWidth", "VariationWidth", XtRInt, sizeof(int), offset(var_wd), XtRImmediate, (caddr_t) 300 }, { "menuWidth", "MenuWidth", XtRInt, sizeof(int), offset(men_wd), XtRImmediate, (caddr_t) 130 }, { "buttonWidth", "ButtonWidth", XtRInt, sizeof(int), offset(but_wd), XtRImmediate, (caddr_t) 164 }, { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), offset(fptr), XtRString, DefaultFont } }; XtAppContext app_context; extern int madechanges; extern void exit(); static Widget toplevel, brd, notify, comm, buts, vars, title; static Pixmap mark; static int move_x = -1, move_y = -1; static int theCommand, AmHelping; static XtActionProc HandleKeyDown(); static void SetCommand(), HandleScoring(), DoVariation(), ShowCaptured(); static void notifyMessage(); static void notifyClear(); static void HandleHelp(), HelpCommand(); static char comment_backup[MAXCOMMENT]; static String menu_name[] = { "File", "Edit", "Score", "Others", "Help", 0 /* sentinel */ }; static Buttons menu_entry[] = { {"Load File", (char *)SetCommand, (caddr_t)C_LOAD }, {"Save File", (char *)SetCommand, (caddr_t)C_WRITE }, {"Next File", (char *)SetCommand, (caddr_t)C_NEXTFILE }, {"Back File", (char *)SetCommand, (caddr_t)C_BACKFILE }, {"Save Short", (char *)SetCommand, (caddr_t)C_SAVESHORT }, {"Save Screen", (char *)SetCommand, (caddr_t)C_SAVESCREEN }, {"Quit", (char *)SetCommand, (caddr_t)C_QUIT }, {0, NULL, 0}, /* sentinel */ {"Add Black", (char *)SetCommand, (caddr_t)C_ADDBLACK }, {"Add White", (char *)SetCommand, (caddr_t)C_ADDWHITE }, {"Add Letter", (char *)SetCommand, (caddr_t)C_ADDLETTER }, {"Add Mark", (char *)SetCommand, (caddr_t)C_ADDMARK }, {"Add Name", (char *)SetCommand, (caddr_t)C_ADDNAME }, {"Add Variation", (char *)SetCommand, (caddr_t)C_ADDVAR }, {"Edit Comment", (char *)SetCommand, (caddr_t)C_EDCOMMENT }, {"Delete Node", (char *)SetCommand, (caddr_t)C_DELNODE }, {"Cut Tree", (char *)SetCommand, (caddr_t)C_TREECUT }, {"Paste", (char *)SetCommand, (caddr_t)C_PASTE }, {0, NULL, 0}, /* sentinel */ {"Start Scoring", (char *)HandleScoring, (caddr_t)C_SCORE }, {"Remove Dead Group", (char *)HandleScoring, (caddr_t)C_MOVE }, {"Abandon Removals", (char *)HandleScoring, (caddr_t)C_UNDO }, {"Quit Scoring", (char *)HandleScoring, (caddr_t)C_QUIT }, {0, NULL, 0}, /* sentinel */ {"Move", (char *)SetCommand, (caddr_t)C_MOVE }, {"Pass", (char *)SetCommand, (caddr_t)C_PASSMOVE }, {"Redraw", (char *)SetCommand, (caddr_t)C_REDRAW }, {"Toggle Color", (char *)SetCommand, (caddr_t)C_TOGGLESTONE }, {"Play", (char *)SetCommand, (caddr_t)C_TOPLAY }, {"Tutor Swap", (char *)SetCommand, (caddr_t)C_TUTORSWAP }, {"Information", (char *)SetCommand, (caddr_t)C_INFO }, {0, NULL, 0}, /* sentinel */ {"On Short", (char *)HandleHelp, (caddr_t)1 }, {"On Long", (char *)HandleHelp, (caddr_t)3 }, /* use next bit */ {"Off", (char *)HandleHelp,(caddr_t)0 }, {0, NULL, 0} /* sentinel */ }; static Buttons buttons[] = { {"Move Forward", (char *)SetCommand, (caddr_t)C_DOWN }, {"Move Backward", (char *)SetCommand, (caddr_t)C_UP }, {"Next Node", (char *)SetCommand, (caddr_t)C_WALKDOWN }, {"Previous Node", (char *)SetCommand, (caddr_t)C_WALKUP }, {"Next Comment", (char *)SetCommand, (caddr_t)C_SEARCHCOMMENT }, {"Previous Comment", (char *)SetCommand, (caddr_t)C_SEARCHBACKCOMMENT }, {"Next Variation", (char *)SetCommand, (caddr_t)C_DOWNFORK }, {"Previous Variation", (char *)SetCommand, (caddr_t)C_UPFORK }, {"End Variation", (char *)SetCommand, (caddr_t)C_END }, {"Beginning Variation", (char *)SetCommand, (caddr_t)C_BEGINNING }, {"Go to Node", (char *)SetCommand, (caddr_t)C_GOTO }, {0, NULL, 0}, /* sentinel */ }; static Buttons variations[MAX_VARS] = { {"unused", (char *)DoVariation, (caddr_t)0 }, {"unused", (char *)DoVariation, (caddr_t)1 }, {"unused", (char *)DoVariation, (caddr_t)2 }, {"unused", (char *)DoVariation, (caddr_t)3 }, {"unused", (char *)DoVariation, (caddr_t)4 }, {"unused", (char *)DoVariation, (caddr_t)5 }, {"unused", (char *)DoVariation, (caddr_t)6 }, {"unused", (char *)DoVariation, (caddr_t)7 }, {"unused", (char *)DoVariation, (caddr_t)8 }, {"unused", (char *)DoVariation, (caddr_t)9 }, {"unused", (char *)DoVariation, (caddr_t)10 }, {"unused", (char *)DoVariation, (caddr_t)11 }, {"unused", (char *)DoVariation, (caddr_t)12 }, {"unused", (char *)DoVariation, (caddr_t)13 }, {"unused", (char *)DoVariation, (caddr_t)14 }, {"unused", (char *)DoVariation, (caddr_t)15 }, {"unused", (char *)DoVariation, (caddr_t)16 }, {"unused", (char *)DoVariation, (caddr_t)17 }, {"unused", (char *)DoVariation, (caddr_t)18 }, {"unused", (char *)DoVariation, (caddr_t)19 }, {"unused", (char *)DoVariation, (caddr_t)20 }, {"unused", (char *)DoVariation, (caddr_t)21 }, {"unused", (char *)DoVariation, (caddr_t)22 }, {"unused", (char *)DoVariation, (caddr_t)23 }, {"unused", (char *)DoVariation, (caddr_t)24 }, {"unused", (char *)DoVariation, (caddr_t)25 }, }; static void Beep() { if( !XtIsRealized(toplevel) ) return; XBell(XtDisplay( toplevel ), 50); } static XtActionProc HandleKeyDown(w, cli, e) Widget w; caddr_t cli, e; { XKeyEvent *evnt = (XKeyEvent *)e; char buf[BUF_SIZE]; KeySym ksym; XComposeStatus status; #ifdef DEBUG fprintf(stderr, "HandleKeyDown: "); #endif XLookupString(evnt, buf, BUF_SIZE, &ksym, &status); #ifdef DEBUG fprintf(stderr, "-%s-\n", buf); #endif switch(*buf) { case '>': theCommand = C_DOWN; break; case '<': theCommand = C_UP; break; case ',': theCommand = C_WALKUP; break; case '{': theCommand = C_SEARCHBACKCOMMENT; break; case '.': theCommand = C_WALKDOWN; break; case '}': theCommand = C_SEARCHCOMMENT; break; case '[': theCommand = C_DOWNFORK; break; case ']': theCommand = C_UPFORK; break; case '#': theCommand = C_LOAD; break; case ' ': /* drop through */ case '0': if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; } else { theCommand = C_MOVE; xcur = move_x; ycur = move_y; } break; case '!': theCommand = C_TREECUT; break; case '^': theCommand = C_PASTE; break; case 'a': Beep(); break; case 'b': theCommand = C_BEGINNING; break; case 'C': theCommand = C_NOTHING; ShowCaptured(); break; case 'c': theCommand = C_EDCOMMENT; break; case 'd': theCommand = C_DELNODE; break; case 'e': theCommand = C_END; break; case 'f': theCommand = C_NEXTFILE; break; case 'g': theCommand = C_GOTO; break; case 'l': if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; } else { theCommand = C_ADDLETTER; xcur = move_x; ycur = move_y; } break; case 'm': if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; } else { theCommand = C_ADDMARK; xcur = move_x; ycur = move_y; } break; case 'n': theCommand = C_ADDNAME; break; case 'p': theCommand = C_PASSMOVE; break; case 'q': theCommand = C_QUIT; break; case 'r': theCommand = C_BACKFILE; break; case 's': theCommand = C_SCORE; break; case 'v': theCommand = C_ADDVAR; break; case 'w': theCommand = C_WRITE; break; case 'x': if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; } else { theCommand = C_ADDWHITE; xcur = move_x; ycur = move_y; } break; case 'z': if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; } else { theCommand = C_ADDBLACK; xcur = move_x; ycur = move_y; } break; /* * These letter apear to not do anything in ascii mgt. */ case 'h': case 'i': case 'j': case 'k': case 'o': case 't': case 'u': case 'y': Beep(); break; default: XtAppWarning(app_context, "Unknow character to the X Version"); break; } } static void dobuttondown(w, cli, call) Widget w; caddr_t cli, call; { XButtonEvent *evnt = (XButtonEvent *)call; #ifdef DEBUG fprintf(stderr, "dobuttondown: %d %d\n", evnt->x, evnt->y); #endif /* DEBUG */ if (evnt->x < 0 || evnt->y < 0) { theCommand = C_NOTHING; return; } if ((move_x == evnt->x) && (move_y == INDEX_TO_POS(evnt->y))) { xcur = move_x; ycur = move_y; theCommand = C_MOVE; return; } move_x = evnt->x; move_y = INDEX_TO_POS(evnt->y); theCommand = C_NOTHING; BWHighlightPiece(brd, move_x, INDEX_TO_POS(move_y)); } static void HandleHelp(w, cli, call) Widget w; caddr_t cli, call; { AmHelping = (int)cli; theCommand = C_NOTHING; } static void DoVariation(w, cli, call) Widget w; caddr_t cli, call; { #ifdef DEBUG fprintf(stderr, "DoVariation\n"); #endif /* DEBUG */ theCommand = C_CHOSECHILD + (int)cli; } static Widget CreateVariationsButtons(parent, left, top) Widget parent, left, top; { Widget ret, form, nextto; int i, j; Arg arg[10]; #ifdef DEBUG fprintf(stderr, "CreateVariationsButtons\n"); #endif /* DEBUG */ i = 0; XtSetArg(arg[i], XtNfromVert, top); i++; XtSetArg(arg[i], XtNfromHoriz, left); i++; XtSetArg(arg[i], XtNwidth, 174); i++; XtSetArg(arg[i], XtNheight, 240); i++; XtSetArg(arg[i], XtNtop, XtChainTop); i++; XtSetArg(arg[i], XtNbottom, XtChainBottom); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; XtSetArg(arg[i], XtNallowVert, True); i++; XtSetArg(arg[i], XtNallowHoriz, True); i++; ret = XtCreateManagedWidget("variations", viewportWidgetClass, parent, arg, i); i = 0; form = XtCreateManagedWidget("form", formWidgetClass, ret, arg, i); i = 0; XtSetArg(arg[i], XtNwidth, 300); i++; XtSetArg(arg[i], XtNborderWidth, 0); i++; XtSetArg(arg[i], XtNfont, reses.fptr); i++; title = XtCreateManagedWidget("title", labelWidgetClass, form, arg, i); for (j=0, nextto=title; j < MAX_VARS; nextto=variations[j].w, j++) { i = 0; XtSetArg(arg[i], XtNfromVert, nextto); i++; XtSetArg(arg[i], XtNwidth, 300); i++; XtSetArg(arg[i], XtNfont, reses.fptr); i++; variations[j].w = XtCreateManagedWidget(variations[j].name, commandWidgetClass, form, arg, i); XtAddCallback(variations[j].w, XtNcallback, variations[j].callback, variations[j].cmd); } return ret; } static Widget CreateMenus (parent) Widget parent; { int i, j, k; Widget ret, button, menu, entry, nextto; Arg arg[10]; #ifdef DEBUG fprintf(stderr, "CreateMenus\n"); #endif /* DEBUG */ j = 0; XtSetArg(arg[j], XtNtop, XtChainTop); j++; XtSetArg(arg[j], XtNbottom, XtChainTop); j++; XtSetArg(arg[j], XtNleft, XtChainLeft); j++; XtSetArg(arg[j], XtNright, XtChainRight); j++; ret = XtCreateManagedWidget("menus", formWidgetClass, parent, arg, j); for (i=0, k=0, nextto=NULL; menu_name[i]; i++, k++, nextto=button) { j = 0; XtSetArg(arg[j], XtNfromHoriz, nextto); j++; XtSetArg(arg[j], XtNwidth, reses.men_wd); j++; XtSetArg(arg[j], XtNfont, reses.fptr); j++; button = XtCreateManagedWidget(menu_name[i], menuButtonWidgetClass, ret, arg, j); j = 0; XtSetArg(arg[j], XtNwidth, reses.men_wd); j++; XtSetArg(arg[j], XtNborderWidth, 3); j++; XtSetArg(arg[j], XtNborderColor, "black"); j++; XtSetArg(arg[j], XtNrowHeight, 20); j++; menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, button, arg, j); for (; menu_entry[k].name; k++) { j = 0; XtSetArg(arg[j], XtNleftMargin, 20); j++; XtSetArg(arg[j], XtNfont, reses.fptr); j++; entry = XtCreateManagedWidget(menu_entry[k].name, smeBSBObjectClass, menu, arg, j); XtAddCallback(entry, XtNcallback, menu_entry[k].callback, menu_entry[k].cmd); } } return ret; } static Widget CreateButtons(parent, left, top ) Widget parent, left, top; { int i, j; Widget ret, nextto, tmp; Arg arg[10]; #ifdef DEBUG fprintf(stderr, "CreateButtons\n"); #endif /* DEBUG */ i = 0; XtSetArg(arg[i], XtNfromVert, top); i++; XtSetArg(arg[i], XtNfromHoriz, left); i++; XtSetArg(arg[i], XtNtop, XtChainTop); i++; XtSetArg(arg[i], XtNbottom, XtChainTop); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; ret = XtCreateManagedWidget("buttons", formWidgetClass, parent, arg, i); for(j = 0, nextto = NULL; buttons[j].name; j++, nextto = tmp) { i = 0; XtSetArg(arg[i], XtNfromVert, nextto); i++; XtSetArg(arg[i], XtNwidth, reses.but_wd); i++; XtSetArg(arg[i], XtNleft, XtChainLeft); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; XtSetArg(arg[i], XtNfont, reses.fptr); i++; tmp = XtCreateManagedWidget(buttons[j].name, commandWidgetClass, ret, arg, i); XtAddCallback(tmp, XtNcallback, buttons[j].callback, buttons[j].cmd); } return ret; } static void openX11() { int i; Arg arg[10]; Widget form, m_holder, t_holder, c_viewer; int argc = 1; #ifdef XMGT_IGS #ifdef XMGT_HFS static char *argv[1] = { "Xmgt + HFS + IGS" }; #else static char *argv[1] = { "Xmgt + IGS" }; #endif /* XMGT_HFS */ #else #ifdef XMGT_HFS static char *argv[1] = { "Xmgt + HFS" }; #else static char *argv[1] = { "Xmgt" }; #endif /* XMGT_HFS */ #endif /* XMGT_IGS */ #ifdef DEBUG fprintf(stderr, "openX11\n"); #endif /* DEBUG */ toplevel = XtAppInitialize(&app_context, "XMgt", NULL, 0, &argc, argv, NULL, NULL, 0); i=0; form = XtCreateManagedWidget("form", formWidgetClass, toplevel, arg, i); XtGetApplicationResources(toplevel, &reses, resources, XtNumber(resources), NULL, 0); m_holder = CreateMenus(form); i=0; XtSetArg(arg[i], XtNfromVert, m_holder); i++; XtSetArg(arg[i], XtNtop, XtChainTop); i++; XtSetArg(arg[i], XtNbottom, XtChainBottom); i++; XtSetArg(arg[i], XtNleft, XtChainLeft); i++; brd = XtCreateManagedWidget("board", boardWidgetClass, form, arg, i); XtAddCallback(brd, XtNbuttonDown, dobuttondown, 0); XtAddCallback(brd, XtNkeyDown, HandleKeyDown, 0); buts = CreateButtons(form, brd, m_holder); vars = CreateVariationsButtons(form, brd, buts); i=0; XtSetArg(arg[i], XtNfromVert, brd); i++; XtSetArg(arg[i], XtNwidth, 684); i++; XtSetArg(arg[i], XtNtop, XtChainBottom); i++; XtSetArg(arg[i], XtNbottom, XtChainBottom); i++; XtSetArg(arg[i], XtNleft, XtChainLeft); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; t_holder = XtCreateManagedWidget("text", formWidgetClass, form, arg, i); i=0; XtSetArg(arg[i], XtNdisplayCaret, False); i++; XtSetArg(arg[i], XtNwidth, reses.note_wd); i++; XtSetArg(arg[i], XtNheight, reses.note_ht); i++; XtSetArg(arg[i], XtNleft, XtChainLeft); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; XtSetArg(arg[i], XtNfont, reses.fptr); i++; notify = XtCreateManagedWidget("notify", asciiTextWidgetClass, t_holder, arg, i); i=0; XtSetArg(arg[i], XtNallowVert, True); i++; XtSetArg(arg[i], XtNfromVert, notify); i++; XtSetArg(arg[i], XtNwidth, reses.note_wd); i++; XtSetArg(arg[i], XtNheight, 173); i++; XtSetArg(arg[i], XtNleft, XtChainLeft); i++; XtSetArg(arg[i], XtNright, XtChainRight); i++; c_viewer = XtCreateManagedWidget("c_viewer", viewportWidgetClass, t_holder, arg, i); i=0; XtSetArg(arg[i], XtNdisplayCaret, False); i++; XtSetArg(arg[i], XtNlength, MAXCOMMENT); i++; XtSetArg(arg[i], XtNwidth, reses.comm_wd); i++; XtSetArg(arg[i], XtNheight, reses.comm_ht); i++; XtSetArg(arg[i], XtNfont, reses.fptr); i++; comm = XtCreateManagedWidget("comment", asciiTextWidgetClass, c_viewer, arg, i); CreateDialog(toplevel); mark = XCreateBitmapFromData(XtDisplay(toplevel), RootWindowOfScreen(XtScreen(toplevel)), xlogo11_bits, xlogo11_width, xlogo11_height); XtRealizeWidget(toplevel); } static void closeX11() { #ifdef DEBUG fprintf(stderr, "closeX11\n"); #endif /* DEBUG */ XtDestroyWidget(toplevel); } static void refreshIOX11() { #ifdef DEBUG fprintf(stderr, "refreshIOX11\n"); #endif /* DEBUG */ } static void plotPiece(b, i, j) pBoard b; int i, j; { piece p; BWPiece bwp; #ifdef DEBUG fprintf(stderr, "plotPiece\n"); #endif /* DEBUG */ p = boardGet(b, i, j); switch( p ) { case P_NOTHING: bwp = Empty; break; case P_BLACK: bwp = Black; break; case P_WHITE: bwp = White; break; case P_DAME: bwp = Dame; break; case P_BLACKTERR: bwp = BlackTerritory; break; case P_WHITETERR: bwp = WhiteTerritory; break; default: assert(0); break; } BWPutPiece( brd, i, INDEX_TO_POS(j), bwp ); } static void displayComment(s) char *s; { static char comment_buffer[MAXCOMMENT]; int i, maxcol; Arg arg[10]; Dimension width; #ifdef DEBUG fprintf(stderr, "displayComment\n"); #endif /* DEBUG */ /* Save unformatted comment so that it can be redisplayed */ strcpy(comment_backup, s); /* Determine the maximum number of characters in a line */ GetSize(comm, &width, NULL); maxcol = (width - 4) / FontWidth; /* Reformat comment so that it is properly wordwrapped */ format(s, comment_buffer, maxcol); /* Display the formatted comment */ SetText(comm, comment_buffer); } static void clearComment() { #ifdef DEBUG fprintf(stderr, "clearComment\n"); #endif /* DEBUG */ SetText(comm, EMPTY_STR); } static void clearBoard() { #ifdef DEBUG fprintf(stderr, "clearBoard\n"); #endif /* DEBUG */ BWReset(brd); } static void clearScreen() { #ifdef DEBUG fprintf(stderr, "clearScreen\n"); #endif /* DEBUG */ } static void HandleScoring(w, cli, call) Widget w; caddr_t cli, call; { static int clkst = 0; static Widget score; Arg args[10]; #ifdef DEBUG fprintf(stderr, "HandleScoring\n"); #endif /* DEBUG */ theCommand = (int) cli; if (clkst == 0) { if (theCommand == C_SCORE) { score = w; clkst = 1; XtSetArg(args[0], XtNlabel, "Calculate Score"); XtSetValues(score, args, 1); } else { theCommand = C_NOTHING; } } else { if (theCommand == C_QUIT) { if (DoAsk(toplevel, "Do you want to quit scoring?") != YES) { theCommand = C_NOTHING; return; } clkst = 0; XtSetArg(args[0], XtNlabel, "Start Scoring"); XtSetValues(score, args, 1); } } } static void SetCommand(w, cli, call) Widget w; caddr_t cli, call; { Arg arglist[5]; Cardinal num_args; #ifdef DEBUG fprintf(stderr, "SetCommand\n"); #endif /* DEBUG */ if( theCommand != C_NOTHING ) { Beep(); return; } switch ((int) cli) { case C_MOVE: case C_ADDBLACK: case C_ADDWHITE: case C_ADDMARK: case C_ADDLETTER: if( move_x == -1 ) { Beep(); theCommand = C_NOTHING; return; } xcur = move_x; ycur = move_y; break; case C_SAVESHORT: if( ! AmHelping ) { num_args = 0; if (saveShort) { XtSetArg(arglist[num_args], XtNleftBitmap, None); num_args++; } else { XtSetArg(arglist[num_args], XtNleftBitmap, mark); num_args++; } XtSetValues(w, arglist, num_args); } break; case C_TUTORSWAP: num_args = 0; if (tutor) { XtSetArg(arglist[num_args], XtNleftBitmap, None); num_args++; } else { XtSetArg(arglist[num_args], XtNleftBitmap, mark); num_args++; } XtSetValues(w, arglist, num_args); break; case C_QUIT: if( ! AmHelping ) { if (DoAsk(toplevel, "Do you want to quit?") != YES) { theCommand = C_NOTHING; return; } } else { HelpCommand((int)C_QUIT); theCommand = C_NOTHING; } break; } theCommand = (int)cli; } static void HelpCommand(cmd) int cmd; { extern char *shortHelpStr[]; extern char *longHelpStr[]; if( cmd == C_NOTHING ) return; #ifdef DEBUG fprintf(stderr, "HelpCommand\n"); #endif /* DEBUG */ if( cmd > 0 && cmd < 45 ) { if( AmHelping & 0x2 ) displayComment(longHelpStr[cmd]); else notifyMessage(shortHelpStr[cmd]); } #ifdef DEBUG else fprintf(stderr, "Unknown cmd %d\n", cmd); #endif /* DEBUG */ } static int getCommand(curnode) nodep curnode; { XEvent evnt; move_x = move_y = -1; theCommand = C_NOTHING; do { if (XtAppPending(app_context)) { XtAppNextEvent(app_context, &evnt); XtDispatchEvent(&evnt); #ifdef XMGT_IGS } else { theCommand = goserver(curnode); #endif /* XMGT_IGS */ } /* Redraw the window if just resized */ if (resized) { reconfig(brd, buts, vars); displayComment(comment_backup); resized = 0; } if( AmHelping ) { HelpCommand(theCommand); theCommand = C_NOTHING; } } while (theCommand == C_NOTHING); return theCommand; } static int getPoint() { #ifdef DEBUG fprintf(stderr, "getPoint\n"); #endif /* DEBUG */ return getCommand(NULL); } static int idle(curnode) nodep curnode; { #ifdef DEBUG fprintf(stderr, "idle\n"); #endif /* DEBUG */ highlightLast(); return getCommand(curnode); } static void drawTree(nd) nodep nd; { property *p; int index; nodep ch; char line[BUF_SIZE]; Arg args[10]; int i; #ifdef DEBUG fprintf(stderr, "drawTree\n"); #endif /* DEBUG */ /* display node number */ XtUnmapWidget(vars); if (p = getprop(nd, t_Name)) sprintf(line, "Node %d: %s", nd->nodeNum, p->data.comment); else sprintf(line, "Node %d:", nd->nodeNum); i=0; XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++; XtSetArg(args[i], XtNlabel, line); i++; XtSetValues(title, args, i); /* display variation buttons */ index = 0; ch = nthChild(nd, 0); while (ch && (index < MAX_VARS)) { XtUnmanageChild(variations[index].w); if (p = getprop(ch, t_Name)) sprintf(line, "Var. %d: %s", index, p->data.comment); else sprintf(line, "Var. %d", index); i = 0; XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++; XtSetArg(args[i], XtNlabel, line); i++; XtSetValues(variations[index].w, args, i); XtManageChild(variations[index].w); ch = NEXTSIBLING(ch); index++; } for( ; index < MAX_VARS ; index++ ) { if( XtIsManaged(variations[index].w) ) XtUnmanageChild(variations[index].w); } XtMapWidget(vars); } static void highlightLastX11(i, j, movenum, turn) int i, j, movenum, turn; { char buf[BUF_SIZE], str[BUF_SIZE]; #ifdef DEBUG fprintf(stderr, "highlightLastX11\n"); #endif /* DEBUG */ if( i == -1 ) { /* I hate this convention */ notifyClear(); return; } if (i == PASSVAL && j == PASSVAL) { sprintf(buf, "%s: %d Pass", turn ? "White" : "Black", movenum); } else { sprintf(buf, "%s: %d @ %c%d", turn ? "White" : "Black", movenum, INDEX_TO_CHAR(i), INDEX_TO_POS(j)+1); BWHighlightPiece(brd, i, INDEX_TO_POS(j)); } sprintf(str, " \tPrisoners: White %d Black %d", prisoners[0], prisoners[1]); strcat(buf, str); if (tutor) strcat(buf," \tMode: tutor"); else if (madechanges) strcat(buf," \tMode: edit "); else strcat(buf," \tMode: read "); if (saveShort) strcat(buf, " short"); else strcat(buf, " long "); notifyMessage((char *)buf); } /* * Any thing here should be in resources. */ static void readEnv() { #ifdef DEBUG fprintf(stderr, "readEnv\n"); #endif /* DEBUG */ } static void notifyMessage(s) char *s; { static char message_buffer[BUF_SIZE]; #ifdef DEBUG fprintf(stderr, "notifyMessage: -%s-\n", s); #endif /* DEBUG */ strcpy(message_buffer, s); SetText(notify, message_buffer); } static void notifyClear() { #ifdef DEBUG fprintf(stderr, "notifyClear\n"); #endif /* DEBUG */ SetText(notify, EMPTY_STR); } static int queryStr(question, answer, len) char *question, *answer; int len; /* bugs, who cares, this is ignored */ { #ifdef DEBUG fprintf(stderr, "queryStr\n"); #endif /* DEBUG */ answer[0] = '\0'; return DoDialog(toplevel, question, answer); } /* * What do I do for this? */ static void setCursor() { #ifdef DEBUG fprintf(stderr, "setCursor\n"); #endif /* DEBUG */ } static void plotMark(b, i, j) pBoard b; int i, j; { #ifdef DEBUG fprintf(stderr, "plotMark\n"); #endif /* DEBUG */ BWSetMark(brd, i, INDEX_TO_POS(j), DiamondMark); } static void plotLetter(i, j, c) int i, j; char c; { #ifdef DEBUG fprintf(stderr, "plotLetter\n"); #endif /* DEBUG */ BWSetLetter(brd, i, INDEX_TO_POS(j), c); } static void editComment(in, out) char *in, **out; { static char comment_buffer[MAXCOMMENT]; char *str; int i; Arg arg[10]; Dimension width; #ifdef DEBUG fprintf(stderr, "editComment\n"); #endif /* DEBUG */ /* Determine the maximum number of characters in a line */ /* Reformat comment so that it is properly wordwrapped */ GetSize(comm, &width, NULL); format(in, comment_buffer, width/FontWidth); i = 0; XtSetArg(arg[i], XtNeditType, XawtextEdit); i++; XtSetArg(arg[i], XtNdisplayCaret, True); i++; XtSetArg(arg[i], XtNstring, comment_buffer); i++; XtSetValues(comm, arg, i); notifyMessage("Edit comment in the comment window directly."); if (DoAsk2(toplevel, "Update comment?", XtGrabNone) == YES) { XtSetArg(arg[0], XtNstring, (XtArgVal)(&str)); XtGetValues(comm, arg, 1); free(in); *out = (char *) malloc(sizeof(char) * strlen(str) + 1); if (*out) strcpy(*out, str); else XtAppWarning(app_context, "Could not alloc in editComment"); } else { *out = in; } notifyClear(); i = 0; XtSetArg(arg[i], XtNeditType, XawtextRead); i++; XtSetArg(arg[i], XtNdisplayCaret, False); i++; XtSetValues(comm, arg, i); } static int askYN(query, deflt) char *query; int deflt; /* will be ignored for now */ { #ifdef DEBUG fprintf(stderr, "askYN\n"); #endif /* DEBUG */ return DoAsk(toplevel, query); } static void notifyError(errormsg) char *errormsg; { #ifdef DEBUG fprintf(stderr, "notifyError\n"); #endif /* DEBUG */ DoWarning(toplevel, errormsg); } static void ShowCaptured() { static char capted[BUF_SIZE]; sprintf(capted, "White %d Black %d", prisoners[0], prisoners[1]); DoWarning(toplevel, capted); } static void displayInfo(s) char *s; { #ifdef DEBUG fprintf(stderr, "displayInfo\n"); #endif /* DEBUG */ displayComment(s); } static char *editName[] = { "Size", "Handicap", "Black's name", "Black's rank", "White's name", "White's rank", "Game name", "Event", "Round", "Date", "Place", "Time limit", "Result", "Game comment", "Source", "User", "Komi" }; static Token getInfoToChange() { static int flag = 0; int code; #ifdef DEBUG fprintf(stderr, "getInfoToChange\n"); #endif /* DEBUG */ if (flag == 1) { flag = 0; return t_BlackRank; } if (flag == 2) { flag = 0; return t_WhiteRank; } code = DoChoice(toplevel); if (code == 0) return t_EOF; else if (code == (t_PlayerBlack-t_Size+1)) flag = 1; else if (code == (t_PlayerWhite-t_Size+1)) flag = 2; return code + t_Size - 1; } static void editInfo(input, output, info_item) char *input; char **output; Token info_item; { char ret[MAXCOMMENT]; #ifdef DEBUG fprintf(stderr, "editInfo\n"); #endif /* DEBUG */ ret[0] = '\0'; if (DoDialog(toplevel, editName[info_item-FIRSTINFO+2], ret) == YES) { if (input) free(input); *output = (char *) malloc(sizeof(char) * strlen(ret) + 1); if (*output) strcpy(*output, ret); else XtAppWarning(app_context, "Could not alloc in editInfo"); } else if (input) { *output = input; } else { *output = (char *) malloc(sizeof(char)); if (!*output) XtAppWarning(app_context, "Could not alloc in editInfo"); **output = '\0'; } } interface asciiInterface = { (char *)0, (char *)0, (char *)0, (pfi) openX11, (pfi) closeX11, (pfi) refreshIOX11, (pfi) plotPiece, (pfi) displayComment, (pfi) clearComment, (pfi) clearBoard, (pfi) clearScreen, (pfi) idle, (pfi) drawTree, (pfi) highlightLastX11, (pfi) readEnv, (pfi) notifyMessage, (pfi) notifyClear, (pfi) queryStr, (pfi) setCursor, (pfi) plotMark, (pfi) plotLetter, (pfi) getPoint, (pfi) editComment, (pfi) askYN, (pfi) notifyError, (pfi) displayInfo, (pfi) getInfoToChange, (pfi) editInfo }; SHAR_EOF fi if test -f 'xutil.c' then echo shar: "will not over-write existing file 'xutil.c'" else cat << \SHAR_EOF > 'xutil.c' /******************************************************************************* * * xutil.c * ******************************************************************************* */ /******************************************************************************* * * Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved. * * This program is distributed in the hope that it will be useful. * Use and copying of this software and preparation of derivative works * based upon this software are permitted, so long as the following * conditions are met: * o credit to the authors is acknowledged following current * academic behaviour * o no fees or compensation are charged for use, copies, or * access to this software * o this copyright notice is included intact. * This software is made available AS IS, and no warranty is made about * the software or its performance. * * Bug descriptions, use reports, comments or suggestions are welcome. * Send them to dumesnil@etca.fr or to: * * Antoine de Maricourt * ETCA CREA-SP * 16 bis, avenue Prieur de la Cote d'Or * 94114 Arcueil Cedex * France * ******************************************************************************* */ /******************************************************************************* * * Rewritten by Chien-Min Wang for xmgt * ******************************************************************************* */ #include <stdio.h> #include <ctype.h> #include <X11/Intrinsic.h> #include <X11/Shell.h> #include <X11/StringDefs.h> #include <X11/Xlib.h> #include <X11/Xos.h> #include <X11/Xatom.h> #include <X11/IntrinsicP.h> #include <X11/ShellP.h> #include <X11/Xaw/Command.h> #include <X11/Xaw/Form.h> #include <X11/Xaw/Label.h> #include <X11/Xaw/AsciiText.h> #include <X11/Xaw/Cardinals.h> #include "xutil.h" #include "FileSel.h" extern Res reses; extern XtAppContext app_context; static Widget f_top; static Widget f_form; static Widget f_msg; static Widget f_sel; static Widget d_top; static Widget d_form; static Widget d_msg; static Widget d_text; static Widget d_confirm; static Widget d_cancel; static Widget a_top; static Widget a_form; static Widget a_msg; static Widget a_confirm; static Widget a_cancel; static Widget w_top; static Widget w_form; static Widget w_msg; static Widget w_confirm; static Widget c_top; static Widget c_form; static Widget c_msg; static Widget c_buttons[20]; static Widget pshell; static int mode; static int done = NO; static int code; static char *choice[] = { "Size", "Handicap", "Black's name", "Black's rank", "White's name", "White's rank", "Game name", "Event", "Round", "Date", "Place", "Time limit", "Result", "Game comment", "Source", "User", "Komi", "Quit", NULL }; static void dialogConfirm(w, cli, call) Widget w; caddr_t cli, call; { XtPopdown(pshell); done = YES; code = YES; } static void dialogCancel(w, cli, call) Widget w; caddr_t cli, call; { XtPopdown(pshell); done = YES; code = NO; } static void DoDialogButton(w, cli, call) Widget w; caddr_t cli, call; { XtPopdown(pshell); done = YES; code = (int) cli; } void CreateDialog (toplevel) Widget toplevel; { static XtActionsRec actions[] = { { "dialogConfirm" , dialogConfirm , }, { "dialogCancel" , dialogCancel , }, }; Arg args[10]; int i, j; XtTranslations translations; XtAppAddActions (app_context, actions, XtNumber(actions)); /* * File Selector */ f_top = XtCreatePopupShell ("file" , transientShellWidgetClass, toplevel , NULL, 0); i = 0; f_form = XtCreateManagedWidget ("form" , formWidgetClass, f_top , args, i); i = 0; XtSetArg (args[i], XtNwidth , (XtArgVal) 500 ); i++; XtSetArg (args[i], XtNborderWidth , (XtArgVal) 0 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; f_msg = XtCreateManagedWidget ("msg" , labelWidgetClass, f_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) f_msg ); i++; XtSetArg (args[i], XtNheight , (XtArgVal) 400 ); i++; XtSetArg (args[i], XtNcheckExistence , (XtArgVal) False ); i++; f_sel = XtCreateManagedWidget ("select" , xfwfFileSelectorWidgetClass, f_form , args, i); XtAddCallback (f_sel, XtNokButtonCallback, (XtCallbackProc)dialogConfirm, NULL); XtAddCallback (f_sel, XtNcancelButtonCallback, (XtCallbackProc)dialogCancel, NULL); XtRealizeWidget (f_top); /* * Dialog Window. */ translations = XtParseTranslationTable ("#override \ <Key> Escape : dialogCancel() \n\ <Key> Linefeed : dialogConfirm() \n\ <Key> Return : dialogConfirm() \n\ Ctrl <Key> J : dialogConfirm() \n\ Ctrl <Key> M : dialogConfirm()"); d_top = XtCreatePopupShell ("dialog" , transientShellWidgetClass, toplevel , NULL, 0); i = 0; XtSetArg (args[i], XtNdefaultDistance , (XtArgVal) 12 ); i++; XtSetArg (args[i], XtNtranslations , (XtArgVal) translations); i++; d_form = XtCreateManagedWidget ("form" , formWidgetClass, d_top , args, i); i = 0; XtSetArg (args[i], XtNwidth , (XtArgVal) 334 ); i++; XtSetArg (args[i], XtNborderWidth , (XtArgVal) 0 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; d_msg = XtCreateManagedWidget ("msg" , labelWidgetClass, d_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) d_msg ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 334 ); i++; XtSetArg (args[i], XtNvertDistance , (XtArgVal) 8 ); i++; XtSetArg (args[i], XtNeditType , (XtArgVal) XawtextEdit ); i++; XtSetArg (args[i], XtNtranslations , (XtArgVal) translations); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; d_text = XtCreateManagedWidget ("text" , asciiTextWidgetClass, d_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) d_text ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i], XtNshapeStyle , (XtArgVal) XmuShapeOval); i++; #endif d_cancel = XtCreateManagedWidget ("cancel" , commandWidgetClass, d_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) d_text ); i++; XtSetArg (args[i], XtNfromHoriz , (XtArgVal) d_cancel ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i], XtNshapeStyle , (XtArgVal) XmuShapeOval); i++; #endif d_confirm = XtCreateManagedWidget ("confirm" , commandWidgetClass, d_form , args, i); XtAddCallback (d_cancel , XtNcallback, dialogCancel , NULL); XtAddCallback (d_confirm, XtNcallback, dialogConfirm, NULL); XtRealizeWidget (d_top); /* * Ask Window. */ a_top = XtCreatePopupShell ("ask" , transientShellWidgetClass, toplevel , NULL, 0); i = 0; XtSetArg (args[i], XtNdefaultDistance, (XtArgVal) 12 ); i++; XtSetArg (args[i], XtNtranslations , (XtArgVal) translations); i++; a_form = XtCreateManagedWidget ("form" , formWidgetClass, a_top , args, i); i = 0; XtSetArg (args[i], XtNwidth , (XtArgVal) 334 ); i++; XtSetArg (args[i], XtNheight , (XtArgVal) 30 ); i++; XtSetArg (args[i], XtNborderWidth , (XtArgVal) 0 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; a_msg = XtCreateManagedWidget ("msg" , labelWidgetClass, a_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) a_msg ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i], XtNshapeStyle , (XtArgVal) XmuShapeOval); i++; #endif a_cancel = XtCreateManagedWidget ("cancel" , commandWidgetClass, a_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) a_msg ); i++; XtSetArg (args[i], XtNfromHoriz , (XtArgVal) a_cancel ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i], XtNshapeStyle , (XtArgVal) XmuShapeOval); i++; #endif a_confirm = XtCreateManagedWidget ("confirm" , commandWidgetClass, a_form , args, i); XtAddCallback (a_cancel , XtNcallback, dialogCancel , NULL); XtAddCallback (a_confirm, XtNcallback, dialogConfirm, NULL); XtRealizeWidget (a_top); /* * Warning Window. */ translations = XtParseTranslationTable ("#override \ <BtnDown> : dialogCancel() \n\ <Key> : dialogCancel()"); w_top = XtCreatePopupShell ("warning" , transientShellWidgetClass, toplevel , NULL, 0); i = 0; XtSetArg (args[i], XtNdefaultDistance, (XtArgVal) 12 ); i++; XtSetArg (args[i], XtNtranslations , (XtArgVal) translations); i++; w_form = XtCreateManagedWidget ("form" , formWidgetClass, w_top , args, i); i = 0; XtSetArg (args[i], XtNwidth , (XtArgVal) 334 ); i++; XtSetArg (args[i], XtNheight , (XtArgVal) 30 ); i++; XtSetArg (args[i], XtNborderWidth , (XtArgVal) 0 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; w_msg = XtCreateManagedWidget ("msg" , labelWidgetClass, w_form , args, i); i = 0; XtSetArg (args[i], XtNfromVert , (XtArgVal) w_msg ); i++; XtSetArg (args[i], XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i], XtNhorizDistance , (XtArgVal) 90 ); i++; XtSetArg (args[i], XtNlabel , (XtArgVal) "Continue" ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i], XtNshapeStyle , (XtArgVal) XmuShapeOval); i++; #endif w_confirm = XtCreateManagedWidget ("confirm" , commandWidgetClass, w_form , args, i); XtAddCallback (w_confirm, XtNcallback, dialogCancel, NULL); XtRealizeWidget (w_top); /* * Choice Window. */ translations = XtParseTranslationTable ("#override \ <BtnDown> : dialogCancel() \n\ <Key> : dialogCancel()"); c_top = XtCreatePopupShell ("choice" , transientShellWidgetClass, toplevel , NULL, 0); i = 0; XtSetArg (args[i], XtNdefaultDistance, (XtArgVal) 12 ); i++; XtSetArg (args[i], XtNtranslations , (XtArgVal) translations); i++; c_form = XtCreateManagedWidget ("form" , formWidgetClass, c_top , args, i); i = 0; XtSetArg (args[i], XtNwidth , (XtArgVal) 334 ); i++; XtSetArg (args[i], XtNborderWidth , (XtArgVal) 0 ); i++; XtSetArg (args[i], XtNfont , (XtArgVal) reses.fptr ); i++; c_msg = XtCreateManagedWidget ("Edit which item?", labelWidgetClass, c_form , args, i); for (j = 0; choice[j]; j++) { i = 0; if (j >= 2) { XtSetArg (args[i], XtNfromVert , (XtArgVal) c_buttons[j-2]); i++; } else { XtSetArg (args[i], XtNfromVert , (XtArgVal) c_msg ); i++; } if (j & 1) { XtSetArg (args[i], XtNfromHoriz , (XtArgVal) c_buttons[j-1]); i++; } XtSetArg (args[i] , XtNwidth , (XtArgVal) 160 ); i++; XtSetArg (args[i] , XtNfont , (XtArgVal) reses.fptr ); i++; #ifndef NO_EXTENSION XtSetArg (args[i] , XtNshapeStyle, (XtArgVal) XmuShapeOval ); i++; #endif c_buttons[j] = XtCreateManagedWidget (choice[j], commandWidgetClass, c_form , args, i); if (choice[j+1]) XtAddCallback (c_buttons[j], XtNcallback, DoDialogButton, j+1); else XtAddCallback (c_buttons[j], XtNcallback, DoDialogButton, 0); } XtRealizeWidget (c_top); } void ClearText(w) Widget w; { SetText(w, ""); } void SetText(w, str) AsciiWidget w; char *str; { int i; Arg args[10]; i = 0; XtSetArg(args[i], XtNstring, str); i++; XtSetValues(w, args, i); } void GetSize(w, width, height) Widget w; Dimension *width, *height; { int i; Arg args[10]; i = 0; XtSetArg(args[i], XtNwidth, width); i++; XtSetArg(args[i], XtNheight, height); i++; XtGetValues(w, args, i); } void format(p1, p2, maxcol) char *p1, *p2; int maxcol; { int count; char *p3; if (p1 == NULL) { *p2 = '\0'; return; } /* Reformat *p1 into *p2 so that the string is properly wordwrapped */ for (count = 0; *p1; p1++, p2++) { *p2 = *p1; count++; if (*p2 == ' ') p3 = p2; if (*p2 == '\n') { p3 = p2; count = 0; } if (count > maxcol) { *p3 = '\n'; count = p2 - p3; } } *p2 = '\0'; } int DoPopupShell(parent, title, query, option) Widget parent; char *title; char *query; XtGrabKind option; { String str; Position x, y; Dimension width, height; Arg arg[10]; int i; XfwfFileSelectorStatusStruct ss; /* get the coords of the middle of parent widget */ GetSize(parent, &width, &height); /* translate coords in application top-level window */ /* into coords from root window origin. */ XtTranslateCoords(parent, (Position) width/4, (Position) height/4, &x, &y); switch (mode) { case LoadFileBox: case SaveFileBox: XtTranslateCoords(parent,(Position)width/8,(Position)height/4,&x,&y); pshell = f_top; XtSetArg(arg[0], XtNlabel, title); XtSetValues(f_msg, arg, 1); /* re-read the current directory and refresh the widget */ XfwfFileSelectorGetStatus(f_sel, &ss); XfwfFileSelectorChangeDirectory(f_sel, ss.path); break; case DialogBox: pshell = d_top; XtSetArg(arg[0], XtNlabel, title); XtSetValues(d_msg, arg, 1); XtSetArg(arg[0], XtNstring, ""); XtSetValues(d_text, arg, 1); break; case AskBox: pshell = a_top; XtSetArg(arg[0], XtNlabel, title); XtSetValues(a_msg, arg, 1); break; case WarningBox: pshell = w_top; XtSetArg(arg[0], XtNlabel, title); XtSetValues(w_msg, arg, 1); break; case ChoiceBox: pshell = c_top; break; } i = 0; XtSetArg(arg[i], XtNx, x); i++; XtSetArg(arg[i], XtNy, y); i++; XtSetValues(pshell, arg, i); XtPopup(pshell, option); while(!done){ XEvent evnt; XtAppNextEvent(app_context, &evnt); XtDispatchEvent(&evnt); } done = NO; if ((mode == LoadFileBox || mode == SaveFileBox) && (code == YES)) { XfwfFileSelectorGetStatus(f_sel, &ss); strcpy(query, ss.path); strcat(query, ss.file_box_text); } else if ((mode == DialogBox) && (code == YES)) { XtSetArg(arg[0], XtNstring, &str); XtGetValues(d_text, arg, 1); strcpy(query, str); } return code; } int DoDialog(parent, title, query) Widget parent; char *title; char *query; { #ifdef XMGT_HFS if (strcmp(title, "Load file? ") == 0) { mode = LoadFileBox; return DoPopupShell(parent, title, query, XtGrabNonexclusive); } else if (strcmp(title, "Save name? ") == 0) { mode = SaveFileBox; return DoPopupShell(parent, title, query, XtGrabNonexclusive); } else if (strcmp(title, "Save screen: ") == 0) { mode = SaveFileBox; return DoPopupShell(parent, title, query, XtGrabNonexclusive); } else { mode = DialogBox; return DoPopupShell(parent, title, query, XtGrabNonexclusive); } #else mode = DialogBox; return DoPopupShell(parent, title, query, XtGrabNonexclusive); #endif /* XMGT_HFS */ } int DoAsk(parent, title) Widget parent; char *title; { mode = AskBox; return DoPopupShell(parent, title, NULL, XtGrabNonexclusive); } int DoAsk2(parent, title, option) Widget parent; char *title; XtGrabKind option; { mode = AskBox; return DoPopupShell(parent, title, NULL, option); } void DoWarning(parent, errmsg) Widget parent; char* errmsg; { mode = WarningBox; DoPopupShell(parent, errmsg, NULL , XtGrabNonexclusive); } int DoChoice(parent) Widget parent; { mode = ChoiceBox; return DoPopupShell(parent, NULL , NULL , XtGrabNonexclusive); } SHAR_EOF fi if test -f 'xutil.h' then echo shar: "will not over-write existing file 'xutil.h'" else cat << \SHAR_EOF > 'xutil.h' /* xutil.h * * Copyright (c) 1992 by Chien-Min Wang and Tim Casey. * All rights reserved. */ #define YES 1 #define NO 0 #define DialogBox 1 #define AskBox 2 #define WarningBox 3 #define ChoiceBox 4 #define LoadFileBox 5 #define SaveFileBox 6 typedef struct { char *name; char *callback; caddr_t cmd; Widget w; } Buttons; typedef struct { int comm_wd, comm_ht, note_wd, note_ht, var_wd, but_wd, men_wd; XFontStruct *fptr; } Res, *ResPtr; void format(); void ClearText(); void SetText(); void CreateDialog(); int DoDialog(); int DoAsk(); int DoAsk2(); void DoWarning(); int DoChoice(); SHAR_EOF fi exit 0 # End of shell archive